Merge "usb: msm_otg: Allow support to use 2nd HSPHY with USB2 Core"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index 4d441ba..6b2f962 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -87,6 +87,10 @@
 			(In Bytes).
 qcom,prio-rd:		Read priority for a BIMC bus master (Can be 0/1/2)
 qcom,prio-wr:		Write priority for a BIMC bus master (Can be 0/1/2)
+qcom,prio0:		Priority low signal for a NoC bus master
+			(Can be 0/1/2).
+qcom,prio1:		Priority high signal for a NoC bus master
+			(Can be 0/1/2)
 
 
 Example:
@@ -149,7 +153,7 @@
 
 - qcom,msm-bus,name:		String representing the client-name
 - qcom,msm-bus,num-cases:	Total number of usecases
-- qcom,msm-bus,active-only:	Context flag for requests in active or
+- qcom,msm-bus,active-only:	Boolean context flag for requests in active or
 				dual (active & sleep) contex
 - qcom,msm-bus,num-paths:	Total number of master-slave pairs
 - qcom,msm-bus,vectors-KBps:	Arrays of unsigned integers representing:
@@ -160,7 +164,7 @@
 
 	qcom,msm-bus,name = "client-name";
 	qcom,msm-bus,num-cases = <3>;
-	qcom,msm-bus,active-only = <0>;
+	qcom,msm-bus,active-only;
 	qcom,msm-bus,num-paths = <2>;
 	qcom,msm-bus,vectors =
 			<22 512 0 0>, <26 512 0 0>,
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 5d1fafb..31600ca 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -19,9 +19,55 @@
 			Typically the sensor closest to CPU0.
 - qcom,poll-ms: Sampling interval to read sensor, in ms.
 - qcom,limit-temp: Threshold temperature to start stepping CPU down, in degC.
-- qcom,temp-hysteresis: Degrees below threshold temperature to step CPU up.
+- qcom,temp-hysteresis: Degrees C below threshold temperature to step CPU up.
 - qcom,freq-step: Number of frequency steps to take on each CPU mitigation.
 
+Optional properties
+
+- qcom,core-limit-temp: Threshold temperature to start shutting down cores
+			in degC
+- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
+			online in sequence.
+- qcom,core-control-mask: The cpu mask that will be used to determine if a
+			core can be controlled or not. A mask of 0 indicates
+			the feature is disabled.
+- qcom,vdd-restriction-temp: When temperature is below this threshold, will
+			enable vdd restriction which will set higher voltage on
+			key voltage rails, in degC.
+- qcom,vdd-restriction-temp-hysteresis: When temperature is above this threshold
+			will disable vdd restriction on key rails, in degC.
+- qcom,pmic-sw-mode-temp: Threshold temperature to disable auto mode on the
+			rail, in degC. If this property exists,
+			qcom,pmic-sw-mode-temp-hysteresis and
+			qcom,pmic-sw-mode-regs need to exist, otherwise return error.
+- qcom,pmic-sw-mode-temp-hysteresis: Degree below threshold temperature to
+			enable auto mode on the rail, in degC. If this property exists,
+			qcom,pmic-sw-mode-temp and qcom,pmic-sw-mode-regs need to
+			exist, otherwise return error.
+- qcom,pmic-sw-mode-regs: Array of the regulator names that will want to
+			disable/enable automode based on the threshold. If this
+			property exists, qcom,pmic-sw-mode-temp and
+			qcom,pmic-sw-mode-temp-hysteresis need to exist, otherwise
+			return error. Also, if this property is defined, will have to
+			define <consumer_supply_name>-supply = <&phandle_of_regulator>
+- <consumer_supply_name>-supply = <&phandle_of_regulator>: consumer_supply_name
+			is the name that's defined in thermal driver.
+			phandle_of_regulator is defined by reuglator device tree.
+
+Optional child nodes
+- qcom,<vdd restriction child node name>: Define the name of the child node.
+			If this property exisits, qcom,vdd-rstr-reg, qcom,levels,
+			qcom,min-level and qcom,freq-req need to exist, otherwise
+			we return an error.
+- qcom,vdd-rstr-reg: Name of the rail
+- qcom,levels: Array of the level values. Unit is corner voltage for voltage request
+			or kHz for frequency request.
+- qcom,min-level: Request this level as minimum level when disabling voltage
+			restriction. Unit is corner voltage for voltage request
+			or kHz for frequency request.
+- qcom,freq-req: Flag to determine if we should restrict frequency on this rail
+			instead of voltage.
+
 Example:
 
 	qcom,msm-thermal {
@@ -31,4 +77,20 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
+		qcom,core-limit-temp = <90>;
+		qcom,core-temp-hysterisis = <10>;
+		qcom,core-control-mask = <7>;
+		qcom,pmic-sw-mode-temp = <90>;
+		qcom,pmic-sw-mode-temp-hysteresis = <80>;
+		qcom,pmic-sw-mode-regs = "vdd_dig";
+		qcom,vdd-restriction-temp = <5>;
+		qcom,vdd-restriction-temp-hysteresis = <10>;
+		vdd_dig-supply=<&pm8841_s2_floor_corner>
+
+		qcom,vdd-dig-rstr{
+			qcom,vdd-rstr-reg = "vdd_dig";
+			qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+			qcom,min-level = <1>; /* No Request */
+		};
 	};
+
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index b9a71f6..7eb65d2 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -9,7 +9,7 @@
   - qcom,ce-hw-instance : should contain crypto HW instance.
   - qcom,msm_bus,name: Should be "qcedev-noc"
   - qcom,msm_bus,num_cases: Depends on the use cases for bus scaling
-  - qcom,msm_bus,active-only: Default vector index
+  - qcom,msm_bus,active-only: Boolean flag for context of request (actve/dual)
   - qcom,msm_bus,num_paths: The paths for source and destination ports
   - qcom,msm_bus,vectors: Vectors for bus topology.
 
@@ -31,7 +31,6 @@
 		qcom,ce-hw-shared;
                 qcom,msm-bus,name = "qcedev-noc";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<56 512 0 0>,
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 59f9879..79dc287 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -9,7 +9,7 @@
   - qcom,ce-hw-instance : should contain crypto HW instance.
   - qcom,msm_bus,name: Should be "qcrypto-noc"
   - qcom,msm_bus,num_cases: Depends on the use cases for bus scaling
-  - qcom,msm_bus,active-only: Default vector index
+  - qcom,msm_bus,active-only: Boolean flag for context of request (actve/dual)
   - qcom,msm_bus,num_paths: The paths for source and destination ports
   - qcom,msm_bus,vectors: Vectors for bus topology.
 
@@ -30,7 +30,6 @@
 		qcom,ce-hw-shared;
                 qcom,msm-bus,name = "qcrypto-noc";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<56 512 0 0>,
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 0004302..436dfc7 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -97,7 +97,6 @@
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
 		qcom,msm-bus,num-cases = <6>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>, <89 604 0 0>,
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 2caa959..ac60e38 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -6,6 +6,8 @@
 - qcom,hfi : supported Host-Firmware Interface, one of:
 	- "venus"
 	- "q6"
+- qcom,max-hw-load: The maximum load the hardware can support expressed in units
+  of macroblocks per second.
 
 Optional properties:
 - reg : offset and length of the register set for the device.
@@ -40,8 +42,6 @@
   (enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
   as "enum cp_mem_usage" in include/linux/msm_ion.h
 - qcom,has-ocmem: indicate the target has ocmem if this property exists
-- qcom,max-hw-load: The maximum load the hardware can support expressed in units
-  of macroblocks per second.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index b99b716..caead84 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -92,7 +92,6 @@
 
 	qcom,msm-bus,name = "sdcc2";
 	qcom,msm-bus,num-cases = <7>;
-	qcom,msm-bus,active-only = <0>;
 	qcom,msm-bus,num-paths = <1>;
 	qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
 			<81 512 6656 13312>, /* 13 MB/s*/
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 87281f7..013d56e 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -155,7 +155,6 @@
 		qcom,cpu-dma-latency-us = <200>;
 		qcom,msm-bus,name = "sdhc2";
 		qcom,msm-bus,num-cases = <7>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
 				<81 512 6656 13312>, /* 13 MB/s*/
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index ad35985..199862f 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -14,6 +14,8 @@
 - vdd_pronto_pll-supply: regulator to supply pronto pll.
 - qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
 - qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-proxy-unvote: GPIO used by the wcnss to trigger proxy unvoting in
+  the Apps
 - qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
 
 Example:
@@ -30,6 +32,7 @@
 
 		/* GPIO input from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index 30d34f6..eb62ea1 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -11,6 +11,9 @@
 
 Optional properties:
  - parent-supply:   phandle to the parent supply/regulator node
+ - qcom,retain-mems: For Oxili GDSCs only: Presence currently denotes a hardware
+		     requirement to assert the forced memory retention signals
+		     in the core's clock branch control register.
 
 Example:
 	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index aaa731e..6a02e86 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -13,6 +13,8 @@
 				register base
 - reg-names:			"apcs_gcc" -string to identify the area where
 				the APCS GCC registers reside.
+- qcom,pfm-threshold		The power coeff threshold in abstract power units below which
+				pmic will be made to operate in PFM mode.
 
 Optional properties:
 - qcom,use-phase-switching	indicates whether the driver should add/shed phases on the PMIC
@@ -51,6 +53,7 @@
 		reg-names = "apcs_gcc";
 		compatible = "qcom,krait-pdn";
 		qcom,use-phase-switching;
+		qcom,pfm-threshold = <376975>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
index 5861eea..9754c2e 100644
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
@@ -77,7 +77,6 @@
 
 		qcom,msm-bus,name = "serial_uart0";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<84 512 0 0>,
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
index c597536..96c9486 100644
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
@@ -93,7 +93,6 @@
 
 		qcom,msm-bus,name = "uart7";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<84 512 0 0>,
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 6ea9e62..8ce31d9 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -74,7 +74,6 @@
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<85 512 0 0>,
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
new file mode 100644
index 0000000..f853285
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -0,0 +1,67 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,mdss_dsi_sharp_qhd_video {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "sharp QHD LS043T1LE01 video mode dsi panel";
+		status = "disable";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,enable-gpio = <&msmgpio 58 0>;
+		qcom,rst-gpio = <&pm8941_gpios 19 0>;
+		qcom,mdss-pan-res = <540 960>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <80 32 48 15 10 3>; /* HBP, HPW, HFP, VBP, VPW, VFP */
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 4095>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <0>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <2>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+		qcom,mdss-pan-dsi-dlane-swap = <0>;
+		qcom,mdss-pan-dsi-t-clk = <0x1c 0x04>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x04>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regulator settings */
+						    20 00 01];
+		qcom,panel-phy-timingSettings = [46 1d 20 00 39 3a
+						    21 21 32 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [00 00 b1 ff           /* BIST Ctrl settings */
+					   00 00];
+		qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+					     00 00 00 00 05 00 00 01 97 /* lane1 config */
+					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
+					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
+					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+		qcom,panel-on-cmds = [05 01 00 00 32 02 01 00 /* sw reset */
+					05 01 00 00 0a 02 11 00 /* exit sleep */
+					15 01 00 00 0a 02 53 2c /* backlight on */
+					15 01 00 00 0a 02 51 ff /* brightness max */
+					05 01 00 00 0a 02 29 00 /* display on */
+					15 01 00 00 0a 02 ae 03 /* set num of lanes */
+					15 01 00 00 0a 02 3a 77 /* rgb_888 */];
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-off-cmds = [05 01 00 00 0a 02 28 00 /* display off */
+					05 01 00 00 78 02 10 00 /* enter sleep */];
+		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index ec42cfc..28766cf 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -88,6 +88,24 @@
 				qcom,fast-avg-setup = <0>;
 			};
 		};
+
+		qcom,pm8110_rtc {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-rtc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			qcom,qpnp-rtc-write = <0>;
+			qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+			qcom,pm8110_rtc_rw@6000 {
+				reg = <0x6000 0x100>;
+			};
+
+			qcom,pm8110_rtc_alarm@6100 {
+				reg = <0x6100 0x100>;
+				interrupts = <0x0 0x61 0x1>;
+			};
+		};
 	};
 
 	qcom,pm8110@1 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index d712e5f..1881311 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -768,6 +768,17 @@
 				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
 			};
+
+			chan@39 {
+				label = "usb_id_nopull";
+				reg = <0x39>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <2>;
+				qcom,fast-avg-setup = <0>;
+			};
 		};
 
 		iadc@3600 {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 0186e54..bf2ab4f 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -99,9 +99,9 @@
 			"MIC BIAS1 Internal1", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
 			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCRight Headset Mic",
 			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC5", "MIC BIAS2 External",
 			"MIC BIAS2 External", "ANCLeft Headset Mic",
 			"DMIC1", "MIC BIAS1 External",
 			"MIC BIAS1 External", "Digital Mic1",
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index 6a8ba3a..bb2f0d4 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -33,7 +33,6 @@
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
 		qcom,msm-bus,num-cases = <4>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 			<26 512 0 0>, <89 604 0 0>,
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index a51d4b8..16a7177 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -176,7 +176,6 @@
 
 		qcom,msm-bus,name = "usb2";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<87 512 0 0>,
@@ -642,8 +641,9 @@
 
 		qcom,firmware-name = "wcnss";
 
-		/* GPIO input from wcnss */
+		/* GPIO inputs from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
@@ -798,6 +798,24 @@
 		reg = <0xfd484000 0x400>;
 		qcom,num-locks = <8>;
 	};
+
+	qcom,qseecom@d980000 {
+		compatible = "qcom,qseecom";
+		reg = <0xd980000 0x256000>;
+		reg-names = "secapp-region";
+		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,hlos-ce-hw-instance = <0>;
+		qcom,qsee-ce-hw-instance = <0>;
+		qcom,msm-bus,name = "qseecom-noc";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 3936000 393600>,
+				<55 512 3936000 393600>,
+				<55 512 3936000 393600>;
+	};
 };
 
 &gdsc_venus {
@@ -917,6 +935,16 @@
 		qcom,fast-avg-setup = <0>;
 	};
 
+	chan@39 {
+		label = "usb_id_nopull";
+		reg = <0x39>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
 };
 
 &pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index c762405..08da115 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -19,7 +19,7 @@
 	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
 	qcom,msm-id = <147 1 0>, <165 1 0>;
 
-	serial@f991f000 {
+	serial@f991e000 {
 		status = "ok";
 	};
 };
@@ -38,7 +38,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
@@ -61,7 +61,7 @@
 
 	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index f3a8259..5e57430 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -33,7 +33,6 @@
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
 		qcom,msm-bus,num-cases = <4>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 			<26 512 0 0>,
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
index 9690d12..91029e2 100644
--- a/arch/arm/boot/dts/msm8610-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -12,8 +12,7 @@
 / {
 	qcom,smp2p-modem {
 		compatible = "qcom,smp2p";
-		reg = <0xfa006000 0x1000>, <0x8 0x0>;
-		reg-names = "irq-reg-base", "irq-reg-offset";
+		reg = <0xf9011008 0x4>;
 		qcom,remote-pid = <1>;
 		qcom,irq-bitmask = <0x4000>;
 		interrupts = <0 27 1>;
@@ -21,8 +20,7 @@
 
 	qcom,smp2p-adsp {
 		compatible = "qcom,smp2p";
-		reg = <0xfa006000 0x1000>, <0x8 0x0>;
-		reg-names = "irq-reg-base", "irq-reg-offset";
+		reg = <0xf9011008 0x4>;
 		qcom,remote-pid = <2>;
 		qcom,irq-bitmask = <0x400>;
 		interrupts = <0 158 1>;
@@ -30,8 +28,7 @@
 
 	qcom,smp2p-wcnss {
 		compatible = "qcom,smp2p";
-		reg = <0xfa006000 0x1000>, <0x8 0x0>;
-		reg-names = "irq-reg-base", "irq-reg-offset";
+		reg = <0xf9011008 0x4>;
 		qcom,remote-pid = <4>;
 		qcom,irq-bitmask = <0x40000>;
 		interrupts = <0 143 1>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index eaf89ee..2013bb8 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -74,6 +74,13 @@
 		status = "disabled";
 	};
 
+	serial@f991e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991e000 0x1000>;
+		interrupts = <0 108 0>;
+		status = "disabled";
+	};
+
 	qcom,vidc@fdc00000 {
 		compatible = "qcom,msm-vidc";
 		qcom,vidc-ns-map = <0x40000000 0x40000000>;
@@ -85,6 +92,35 @@
 		qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
 	};
 
+	qcom,usbbam@f9a44000 {
+		compatible = "qcom,usb-bam-msm";
+		reg = <0xf9a44000 0x11000>;
+		reg-names = "hsusb";
+		interrupts = <0 135 0>;
+		interrupt-names = "hsusb";
+		qcom,usb-bam-num-pipes = <16>;
+		qcom,usb-bam-fifo-baseaddr = <0xfe803000>;
+		qcom,ignore-core-reset-ack;
+		qcom,disable-clk-gating;
+
+		qcom,pipe0 {
+			label = "hsusb-qdss-in-0";
+			qcom,usb-bam-mem-type = <3>;
+			qcom,bam-type = <1>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <1>;
+			qcom,src-bam-physical-address = <0xfc37c000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0xf9a44000>;
+			qcom,dst-bam-pipe-index = <2>;
+			qcom,data-fifo-offset = <0x0>;
+			qcom,data-fifo-size = <0x600>;
+			qcom,descriptor-fifo-offset = <0x600>;
+			qcom,descriptor-fifo-size = <0x200>;
+		};
+	};
+
 	usb@f9a55000 {
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9a55000 0x400>;
@@ -371,13 +407,18 @@
 
 		qcom,firmware-name = "wcnss";
 
-		/* GPIO input from wcnss */
+		/* GPIO inputs from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
 	};
 
+	qcom,iris-fm {
+		compatible = "qcom,iris_fm";
+	};
+
 	sound {
 		compatible = "qcom,msm8x10-audio-codec";
 		qcom,model = "msm8x10-snd-card";
@@ -483,6 +524,25 @@
 		compatible = "qcom,msm-pcm-hostless";
 	};
 
+	qcom,wcnss-wlan@fb000000 {
+		compatible = "qcom,wcnss_wlan";
+		reg = <0xfb000000 0x280000>;
+		reg-names = "wcnss_mmio";
+		interrupts = <0 145 0>, <0 146 0>;
+		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+		qcom,pronto-vddmx-supply = <&pm8110_l3>;
+		qcom,pronto-vddcx-supply = <&pm8110_s1>;
+		qcom,pronto-vddpx-supply = <&pm8110_l6>;
+		qcom,iris-vddxo-supply = <&pm8110_l10>;
+		qcom,iris-vddrfa-supply = <&pm8110_l5>;
+		qcom,iris-vddpa-supply = <&pm8110_l16>;
+		qcom,iris-vdddig-supply = <&pm8110_l5>;
+
+		gpios = <&msmgpio 23 0>, <&msmgpio 24 0>, <&msmgpio 25 0>, <&msmgpio 26 0>, <&msmgpio 27 0>;
+		qcom,has_pronto_hw;
+	};
+
 	qcom,mss@fc880000 {
 		compatible = "qcom,pil-q6v5-mss";
 		reg = <0xfc880000 0x100>,
@@ -543,6 +603,18 @@
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
 	};
+
+	qcom,ipc-spinlock@fd484000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0xfd484000 0x400>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,bam_dmux@fc834000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0xfc834000 0x7000>;
+		interrupts = <0 29 1>;
+	};
 };
 
 &gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index cebb907..bb4b48e 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -284,8 +284,8 @@
 			qcom,qport = <0>;
 			qcom,mas-hw-id = <18>;
 			qcom,mode = "Fixed";
-			qcom,prio-rd = <2>;
-			qcom,prio-wr = <2>;
+			qcom,prio1 = <2>;
+			qcom,prio0 = <2>;
 		};
 
 		mas-qdss-bam {
@@ -296,8 +296,8 @@
 			qcom,mode = "Fixed";
 			qcom,qport = <1>;
 			qcom,mas-hw-id = <19>;
-			qcom,prio-rd = <1>;
-			qcom,prio-wr = <1>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
 			qcom,hw-sel = "NoC";
 		};
 
@@ -342,8 +342,8 @@
 			qcom,mas-hw-id = <29>;
 			qcom,slv-hw-id = <28>;
 			qcom,mode = "Fixed";
-			qcom,prio-rd = <2>;
-			qcom,prio-wr = <2>;
+			qcom,prio1 = <2>;
+			qcom,prio0 = <2>;
 		};
 
 		fab-ovnoc {
@@ -364,8 +364,8 @@
 			qcom,qport = <2>;
 			qcom,mas-hw-id = <23>;
 			qcom,hw-sel = "NoC";
-			qcom,prio-rd = <1>;
-			qcom,prio-wr = <1>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
 		};
 
 		mas-crypto-core1 {
@@ -377,8 +377,8 @@
 			qcom,qport = <3>;
 			qcom,mas-hw-id = <24>;
 			qcom,hw-sel = "NoC";
-			qcom,prio-rd = <1>;
-			qcom,prio-wr = <1>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
 		};
 
 		mas-lpass-proc {
@@ -389,8 +389,8 @@
 			qcom,qport = <4>;
 			qcom,mas-hw-id = <25>;
 			qcom,mode = "Fixed";
-			qcom,prio-rd = <2>;
-			qcom,prio-wr = <2>;
+			qcom,prio1 = <2>;
+			qcom,prio0 = <2>;
 		};
 
 		mas-mss {
@@ -435,8 +435,8 @@
 			qcom,qport = <10>;
 			qcom,mode = "Fixed";
 			qcom,mas-hw-id = <31>;
-			qcom,prio-rd = <1>;
-			qcom,prio-wr = <1>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
 			qcom,hw-sel = "NoC";
 		};
 
@@ -448,8 +448,8 @@
 			qcom,mode = "Fixed";
 			qcom,qport = <11>;
 			qcom,mas-hw-id = <32>;
-			qcom,prio-rd = <1>;
-			qcom,prio-wr = <1>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
 			qcom,hw-sel = "NoC";
 			qcom,iface-clk-node = "msm_usb3";
 		};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 41e3783..91d3bc0 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -229,7 +229,6 @@
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<85 512 0 0>,
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index ec8a459..de370e7 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -276,7 +276,6 @@
 };
 
 &sdcc1 {
-	qcom,bus-width = <4>;
 	status = "disabled";
 };
 
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 28d1d61..3779dbd 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -33,7 +33,6 @@
 		/* Bus Scale Settings */
 		qcom,msm-bus,name = "grp3d";
 		qcom,msm-bus,num-cases = <6>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>, <89 604 0 0>,
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 0f38e44..0ae20a0 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -382,7 +382,6 @@
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
-			qcom,msm-bus,active-only = <0>;
 			qcom,msm-bus,num-paths = <1>;
 			qcom,msm-bus,vectors-KBps =
 					<85 512 0 0>,
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 5c42b2c..88641f9 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -49,7 +49,7 @@
 				     <0x017C 0x0FFF0FFF>,
 				     <0x0160 0x22222222>,
 				     <0x0164 0x00002222>;
-		qcom,mdp-settings = <0x02E0 0x000000AA>,
+		qcom,mdp-settings = <0x02E0 0x000000E9>,
 				    <0x02E4 0x00000055>,
 				    <0x03AC 0xC0000CCC>,
 				    <0x03B4 0xC0000CCC>,
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 5970e6b..a81fc20 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -369,57 +369,99 @@
 
 &pm8941_gpios {
 	gpio@c000 { /* GPIO 1 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c200 { /* GPIO 3 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
 		qcom,vin-sel = <2>;
-		qcom,src-sel = <0>;
+		qcom,src-sel = <0>;	/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c300 { /* GPIO 4 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,src-sel = <0>;
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,vin-sel = <2>;     /* QPNP_PIN_VIN2  */
+		qcom,src-sel = <0>;	/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c400 { /* GPIO 5 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,src-sel = <0>;
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,vin-sel = <2>;     /* QPNP_PIN_VIN2  */
+		qcom,src-sel = <0>;	/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c500 { /* GPIO 6 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c600 { /* GPIO 7 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c700 { /* GPIO 8 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <0>;        /* QPNP_PIN_PULL_UP_30  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c800 { /* GPIO 9 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c900 { /* GPIO 10 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@ca00 { /* GPIO 11 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@cb00 { /* GPIO 12 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@cc00 { /* GPIO 13 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@cd00 { /* GPIO 14 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@ce00 { /* GPIO 15 */
@@ -438,7 +480,7 @@
 		qcom,pull = <5>;
 		qcom,vin-sel = <2>;
 		qcom,out-strength = <3>;
-		qcom,src-sel = <2>;
+		qcom,src-sel = <3>;       /* QPNP_PIN_SEL_FUNC_2  */
 		qcom,master-en = <1>;
 	};
 
@@ -453,60 +495,102 @@
 		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
 		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
 		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
-		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
+		qcom,out-strength = <1>;	/* QPNP_PIN_OUT_STRENGTH_LOW */
 		qcom,src-sel = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
 		qcom,master-en = <1>;
 	};
 
 	gpio@d300 { /* GPIO 20 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@d400 { /* GPIO 21 */
 	};
 
 	gpio@d500 { /* GPIO 22 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@d600 { /* GPIO 23 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@d700 { /* GPIO 24 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@d800 { /* GPIO 25 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@d900 { /* GPIO 26 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
+		qcom,master-en = <1>;
 	};
 
 	gpio@da00 { /* GPIO 27 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@db00 { /* GPIO 28 */
 	};
 
 	gpio@dc00 { /* GPIO 29 */
-		qcom,pull = <0>; /* set to default pull */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,src-sel = <2>;       /* QPNP_PIN_SEL_FUNC_1  */
 		qcom,master-en = <1>;
-		qcom,vin-sel = <2>; /* select 1.8 V source */
 	};
 
 	gpio@dd00 { /* GPIO 30 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@de00 { /* GPIO 31 */
 	};
 
 	gpio@df00 { /* GPIO 32 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@e000 { /* GPIO 33 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@e100 { /* GPIO 34 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@e200 { /* GPIO 35 */
+		qcom,mode = <0>;        /* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <4>;	/* QPNP_PIN_PULL_DN */
+		qcom,master-en = <1>;
 	};
 
 	gpio@e300 { /* GPIO 36 */
@@ -520,6 +604,9 @@
 	};
 
 	mpp@a100 { /* MPP 2 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,master-en = <1>;
 	};
 
 	mpp@a200 { /* MPP 3 */
@@ -534,6 +621,7 @@
 		qcom,output-type = <0>; /* CMOS */
 		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
 		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
 		qcom,master-en = <1>; /* ENABLE MPP */
 	};
 
@@ -543,13 +631,20 @@
 		qcom,output-type = <0>; /* CMOS */
 		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
 		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
 		qcom,master-en = <1>; /* ENABLE MPP */
 	};
 
 	mpp@a600 { /* MPP 7 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,master-en = <1>;
 	};
 
 	mpp@a700 { /* MPP 8 */
+		qcom,mode = <1>;          /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
+		qcom,master-en = <1>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 05451671..49450f3 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -448,6 +448,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
+		qcom,pfm-threshold = <376975>;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 0f762a8..8f2ef31 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -25,3 +25,7 @@
 &pm8941_chg {
 	qcom,chg-charging-disabled;
 };
+
+&sdcc1 {
+	qcom,bus-width = <4>;
+};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index a0b9be6..ec6b14a 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -188,7 +188,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <1>;
 			qcom,ss-power = <784>;
 			qcom,energy-overhead = <190000>;
@@ -205,7 +205,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <75>;
 			qcom,ss-power = <735>;
 			qcom,energy-overhead = <77341>;
@@ -223,7 +223,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <95>;
 			qcom,ss-power = <725>;
 			qcom,energy-overhead = <99500>;
@@ -240,7 +240,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <2000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
@@ -257,7 +257,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
 			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <3000>;
 			qcom,ss-power = <110>;
 			qcom,energy-overhead = <1250300>;
@@ -446,9 +446,9 @@
 		qcom,offset-page-indices = <56>;
 	};
 
-	qcom,rpm-stats@0xfc19dbd0{
+	qcom,rpm-stats@fc19dba0 {
 		compatible = "qcom,rpm-stats";
-		reg = <0xfc19dbd0 0x1000>;
+		reg = <0xfc19dba0 0x1000>;
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 24b68b5..41837c1 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -188,7 +188,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <1>;
 			qcom,ss-power = <784>;
 			qcom,energy-overhead = <190000>;
@@ -205,7 +205,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <75>;
 			qcom,ss-power = <735>;
 			qcom,energy-overhead = <77341>;
@@ -223,7 +223,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <95>;
 			qcom,ss-power = <725>;
 			qcom,energy-overhead = <99500>;
@@ -240,7 +240,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <2000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
@@ -257,7 +257,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
 			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <3000>;
 			qcom,ss-power = <110>;
 			qcom,energy-overhead = <1250300>;
@@ -446,9 +446,9 @@
 		qcom,offset-page-indices = <56>;
 	};
 
-	qcom,rpm-stats@0xfc19dbd0{
+	qcom,rpm-stats@fc19dba0 {
 		compatible = "qcom,rpm-stats";
-		reg = <0xfc19dbd0 0x1000>;
+		reg = <0xfc19dba0 0x1000>;
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 50fb380..777d26c 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -57,8 +57,6 @@
 
 &mdss_mdp {
 	qcom,vbif-settings = <0x0004 0x00000001>;
-	qcom,mdp-settings = <0x02E0 0x000000A9>,
-			    <0x02E4 0x00000055>;
 
 	qcom,mdss-wb-off = <0x00011100 0x00011500
 			    0x00011900 0x00011D00 0x00012100>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 56234a1..273c677 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -102,6 +102,7 @@
 	qcom,vidc {
 		compatible = "qcom,msm-vidc";
 		qcom,hfi = "q6";
+		qcom,max-hw-load = <108000>; /* 720p @ 30 */
 	};
 
 	qcom,wfd {
@@ -130,7 +131,6 @@
 
 		qcom,msm-bus,name = "serial_uart2";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<84 512 0 0>,
@@ -157,7 +157,6 @@
 
 		qcom,msm-bus,name = "usb2";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<87 512 0 0>,
@@ -198,7 +197,6 @@
 
 		qcom,msm-bus,name = "sdcc1";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
 				<78 512 1600 3200>,    /* 400 KB/s*/
@@ -245,7 +243,6 @@
 
 		qcom,msm-bus,name = "sdcc2";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
 				<81 512 1600 3200>,    /* 400 KB/s*/
@@ -292,7 +289,6 @@
 
 		qcom,msm-bus,name = "sdcc3";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <79 512 0 0>, /* No vote */
 				<79 512 1600 3200>,    /* 400 KB/s*/
@@ -338,7 +334,6 @@
 
 		qcom,msm-bus,name = "sdcc4";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <80 512 0 0>, /* No vote */
 				<80 512 1600 3200>,    /* 400 KB/s*/
@@ -365,7 +360,6 @@
 
 		qcom,msm-bus,name = "sdhc1";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
 				<78 512 1600 3200>,    /* 400 KB/s*/
@@ -392,7 +386,6 @@
 
 		qcom,msm-bus,name = "sdhc2";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
 				<81 512 1600 3200>,    /* 400 KB/s*/
@@ -426,7 +419,6 @@
 
 		qcom,msm-bus,name = "sdhc3";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <79 512 0 0>, /* No vote */
 				<79 512 1600 3200>,    /* 400 KB/s*/
@@ -460,7 +452,6 @@
 
 		qcom,msm-bus,name = "sdhc4";
 		qcom,msm-bus,num-cases = <8>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <80 512 0 0>, /* No vote */
 				<80 512 1600 3200>,    /* 400 KB/s*/
@@ -734,7 +725,6 @@
 
 		qcom,msm-bus,name = "usb3";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<61 512 0 0>,
@@ -1002,7 +992,6 @@
 		compatible = "qcom,msm-ocmem-audio";
 		qcom,msm-bus,name = "audio-ocmem";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 			<11 604 0 0>,
@@ -1055,8 +1044,9 @@
 
 		qcom,firmware-name = "wcnss";
 
-		/* GPIO input from wcnss */
+		/* GPIO inputs from wcnss */
 		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
 
 		/* GPIO output to wcnss */
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
@@ -1142,7 +1132,6 @@
 		qcom,qsee-ce-hw-instance = <0>;
 		qcom,msm-bus,name = "qseecom-noc";
 		qcom,msm-bus,num-cases = <4>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<55 512 0 0>,
@@ -1223,7 +1212,6 @@
 		qcom,ce-hw-instance = <1>;
                 qcom,msm-bus,name = "qcedev-noc";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<56 512 0 0>,
@@ -1240,7 +1228,6 @@
 		qcom,ce-hw-instance = <1>;
                 qcom,msm-bus,name = "qcrypto-noc";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<56 512 0 0>,
@@ -1303,6 +1290,29 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
+		qcom,core-limit-temp = <80>;
+		qcom,core-temp-hysteresis = <10>;
+		qcom,core-control-mask = <0xe>;
+		qcom,vdd-restriction-temp = <5>;
+		qcom,vdd-restriction-temp-hysteresis = <10>;
+		qcom,pmic-sw-mode-temp = <90>;
+		qcom,pmic-sw-mode-temp-hysteresis = <70>;
+		qcom,pmic-sw-mode-regs = "vdd_dig";
+		vdd_dig-supply = <&pm8841_s2_floor_corner>;
+		vdd_gfx-supply = <&pm8841_s4_floor_corner>;
+
+		qcom,vdd-dig-rstr{
+			qcom,vdd-rstr-reg = "vdd_dig";
+			qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+			qcom,min-level = <1>; /* No Request */
+		};
+
+		qcom,vdd-gfx-rstr{
+			qcom,vdd-rstr-reg = "vdd_gfx";
+			qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+			qcom,min-level = <1>; /* No Request */
+		};
+
 	};
 
 	qcom,bam_dmux@fc834000 {
@@ -1330,7 +1340,6 @@
 		qcom,bam-rx-ep-pipe-index = <1>;
 		qcom,msm-bus,name = "uart7";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<84 512 0 0>,
@@ -1455,6 +1464,7 @@
 };
 
 &gdsc_oxili_gx {
+	qcom,retain-mems;
 	status = "ok";
 };
 
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 51a3faa..3e421a8 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -80,7 +80,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <100>;
 			qcom,ss-power = <8000>;
 			qcom,energy-overhead = <100000>;
@@ -97,7 +97,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <2000>;
 			qcom,ss-power = <5000>;
 			qcom,energy-overhead = <60100000>;
@@ -114,7 +114,7 @@
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
 			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <3500>;
 			qcom,ss-power = <5000>;
 			qcom,energy-overhead = <60350000>;
@@ -131,7 +131,7 @@
 			qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
 			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
 			qcom,irqs-detectable;
-			qcom.gpios-detectable;
+			qcom,gpio-detectable;
 			qcom,latency-us = <4500>;
 			qcom,ss-power = <5000>;
 			qcom,energy-overhead = <60350000>;
@@ -289,9 +289,9 @@
 		qcom,offset-page-indices = <56>;
 	};
 
-	qcom,rpm-stats@fc19dbd0 {
+	qcom,rpm-stats@fc19dba0 {
 		compatible = "qcom,rpm-stats";
-		reg = <0xfc19dbd0 0x1000>;
+		reg = <0xfc19dba0 0x1000>;
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index ee61dc3..0e98aa8 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -101,7 +101,6 @@
 
 		qcom,msm-bus,name = "usb2";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<87 512 0 0>,
@@ -118,7 +117,6 @@
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<85 512 0 0>,
diff --git a/arch/arm/boot/dts/msmkrypton-sim.dts b/arch/arm/boot/dts/msmkrypton-sim.dts
new file mode 100644
index 0000000..1872a36
--- /dev/null
+++ b/arch/arm/boot/dts/msmkrypton-sim.dts
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msmkrypton.dtsi"
+
+/ {
+	model = "Qualcomm MSM KRYPTON SIM";
+	compatible = "qcom,msmkrypton-sim", "qcom,msmkrypton", "qcom,sim";
+	qcom,msm-id = <187 16 0>;
+};
+
+&uartdm3{
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
new file mode 100644
index 0000000..db61dab
--- /dev/null
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -0,0 +1,54 @@
+/* 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/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MSM KRYPTON";
+	compatible = "qcom,msmkrypton";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@f9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xf9000000 0x1000>,
+		      <0xf9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+		ngpio = <89>;
+		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
+	};
+
+	timer: msm-qtimer@f9021000 {
+		compatible = "arm,armv7-timer";
+		reg = <0xf9021000 0x1000>;
+		interrupts = <0 7 0>;
+		irq-is-not-percpu;
+		clock-frequency = <19200000>;
+	};
+
+	uartdm3: serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 45f0868..7e835f6 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -267,6 +267,8 @@
 CONFIG_MSMB_CAMERA=y
 CONFIG_OV9724=y
 CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
 CONFIG_MSM_VIDC_V4L2=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
@@ -375,3 +377,4 @@
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
diff --git a/arch/arm/configs/msmkrypton_defconfig b/arch/arm/configs/msmkrypton_defconfig
new file mode 100644
index 0000000..69bc36e
--- /dev/null
+++ b/arch/arm/configs/msmkrypton_defconfig
@@ -0,0 +1,116 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSMKRYPTON=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_UARTDM_Core_v14=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_RUNTIME=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_MSM_NAND is not set
+CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_ANDROID_PMEM is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_EXT3_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 601fcfa..c510889 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -391,6 +391,21 @@
 	select MEMORY_HOLE_CARVEOUT
 	select MSM_RPM_LOG
 
+config ARCH_MSMKRYPTON
+	bool "MSMKRYPTON"
+	select ARM_GIC
+	select CPU_V7
+	select MSM_GPIOMUX
+	select MSM_RPM_SMD
+	select MSM_NATIVE_RESTART
+	select MSM_RESTART_V2
+	select MSM_SPM_V2
+	select MSM_PM8X60 if PM
+	select MULTI_IRQ_HANDLER
+	select GPIO_MSM_V3
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+
 config ARCH_MSM8610
 	bool "MSM8610"
 	select ARM_GIC
@@ -1074,6 +1089,7 @@
 	default "0x00000000" if ARCH_MSM8610
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00200000" if ARCH_MSM9625
+	default "0x00200000" if ARCH_MSMKRYPTON
 	default "0x00200000" if !MSM_STACKED_MEMORY
 	default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
 	default "0x20000000" if ARCH_QSD8X50
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 1c14ac6..7c78395 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -121,6 +121,7 @@
 ifndef CONFIG_ARCH_MPQ8092
 ifndef CONFIG_ARCH_MSM8610
 ifndef CONFIG_ARCH_MSMZINC
+ifndef CONFIG_ARCH_MSMKRYPTON
 	obj-y += nand_partitions.o
 endif
 endif
@@ -131,6 +132,7 @@
 endif
 endif
 endif
+endif
 obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
 obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
 obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -304,6 +306,7 @@
 obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
+obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o acpuclock-cortex.o
 obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
@@ -368,6 +371,7 @@
 obj-$(CONFIG_ARCH_MSM9615) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMKRYPTON) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index e3b8d73..f20f6ae 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -62,6 +62,9 @@
    zreladdr-$(CONFIG_ARCH_MSMZINC)	:= 0x00008000
         dtb-$(CONFIG_ARCH_MSMZINC)	+= msmzinc-sim.dtb
 
+# MSMKRYPTON
+   zreladdr-$(CONFIG_ARCH_MSMKRYPTON)	:= 0x00208000
+	dtb-$(CONFIG_ARCH_MSMKRYPTON)	+= msmkrypton-sim.dtb
 
 # MSM9615
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index c60e89a..a61f5ca 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -128,122 +128,122 @@
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 3200000 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 3200000 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 3200000 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 3200000 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 3200000 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 229 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 298 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 321 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 346 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 397 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 423 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 506 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 3200000 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 3200000 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 3200000 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 3200000 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 3200000 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  835000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  845000, 229 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  905000, 298 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  920000, 321 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  940000, 346 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  980000, 397 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  995000, 423 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 506 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 3200000 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 3200000 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 3200000 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 229 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 298 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 321 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 346 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 397 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 423 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 506 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 3200000 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 3200000 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 3200000 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   825000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   825000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   825000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   825000, 124 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   825000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   825000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  825000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 229 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 298 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 321 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  915000, 346 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  930000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  945000, 397 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 423 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  975000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  990000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1000000, 506 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_v1_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),  825000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),  825000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),  825000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),  825000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),  825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),  825000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),  825000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 }, L2(10), 825000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(10), 825000, 3200000 },
-	{ 0, {  960000, HFPLL, 1,  50 }, L2(10), 825000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10), 825000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12), 835000, 3200000 },
-	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12), 855000, 3200000 },
-	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12), 870000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12), 885000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16), 900000, 3200000 },
-	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16), 910000, 3200000 },
-	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 925000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 940000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 950000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),  825000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),  825000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),  825000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),  825000, 124 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),  825000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),  825000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),  825000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10), 825000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10), 825000, 229 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10), 825000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10), 825000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12), 835000, 298 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12), 855000, 321 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12), 870000, 346 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12), 885000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16), 900000, 397 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16), 910000, 423 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 925000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 940000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 950000, 506 },
 	{ 0, { 0 } }
 };
 
@@ -284,618 +284,618 @@
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  815000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  825000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  835000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  845000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  855000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  865000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  875000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  890000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  900000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  915000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  925000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  940000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  950000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  965000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  980000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  995000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1010000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1025000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1040000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1055000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1070000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1085000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1100000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  815000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  825000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  835000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  845000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  855000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  865000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  875000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  890000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  900000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  915000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  925000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  940000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  950000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  965000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  980000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  995000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1010000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1025000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1040000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1055000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1070000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1085000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1100000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  810000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  820000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  830000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  840000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  850000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  860000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  875000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  885000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  895000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  910000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  920000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  930000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  945000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  960000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  975000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  990000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1005000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1020000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1030000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1045000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1060000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  810000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  820000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  830000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  840000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  850000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  860000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  875000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  885000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  895000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  910000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  920000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  930000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  945000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  960000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  975000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  990000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17), 1005000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1020000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1030000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1045000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1060000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  785000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  795000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  910000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  955000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  970000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1005000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1020000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1035000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  785000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  795000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  910000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  955000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  970000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1005000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1020000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1035000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  780000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  790000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  935000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  970000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  985000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  995000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1010000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  780000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  790000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  935000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  970000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  985000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  995000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1010000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  780000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  790000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  950000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  960000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  975000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  985000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  780000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  790000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  950000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  960000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  975000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  985000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  760000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  770000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  860000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  870000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  880000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  930000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  940000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  955000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  965000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  975000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  760000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  770000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  860000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  870000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  880000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  930000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  940000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  955000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  965000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  975000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  760000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  770000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  905000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  73 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  760000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  770000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 252 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 275 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 298 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 321 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 346 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 371 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 397 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 423 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  905000, 450 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 477 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 506 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 536 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 567 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 598 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  915000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  950000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  965000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1010000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1025000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1040000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1055000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1070000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1085000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1100000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  805000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  815000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  825000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  835000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  845000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  855000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  865000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  875000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  915000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  925000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  950000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  965000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  980000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  995000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1010000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1025000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1040000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1055000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1070000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1085000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1100000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  920000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  930000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  945000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  975000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  990000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1005000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1020000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  885000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  895000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  920000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  930000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  945000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  960000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  975000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  990000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1005000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1020000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  785000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  795000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  805000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  815000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  825000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  835000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  845000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  910000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  980000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  995000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  785000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  795000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  805000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  815000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  825000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  835000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  845000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  855000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  910000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  980000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  995000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  960000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  970000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  985000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  995000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  960000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  970000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  985000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  995000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  870000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  880000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  920000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  940000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  950000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  975000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  985000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  870000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  880000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  920000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  940000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  950000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  975000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  985000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  890000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  920000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  940000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  955000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  965000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  975000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  890000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  920000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  940000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  955000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  965000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  975000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p2g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  875000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  920000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  930000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 3200000 },
-	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  950000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 102 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 121 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 141 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 161 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 181 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 202 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 223 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 245 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 267 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 289 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 313 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 336 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 360 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 383 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 409 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  875000, 435 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 461 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 488 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 516 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 543 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  920000, 573 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  930000, 604 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 636 },
+	{ 1, { 2150400, HFPLL, 1, 112 }, L2(19),  950000, 656 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 691 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  875000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  885000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  945000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  960000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  975000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  990000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1005000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  875000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  885000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  895000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  945000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  960000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  975000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  990000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1005000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  785000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  795000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  805000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  815000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  825000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  835000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  845000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  855000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  865000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  940000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  955000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  970000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  785000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  795000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  805000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  815000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  825000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  835000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  845000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  855000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  865000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  875000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  940000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  955000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  970000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  925000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  935000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  950000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  960000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  985000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  925000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  935000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  950000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  960000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  985000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  895000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  910000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  895000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  910000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  880000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  890000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  910000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  920000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  965000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  760000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  770000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  880000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  890000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  910000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  920000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  965000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_2p3g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  400000 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 3200000 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 3200000 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  760000, 3200000 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  770000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  780000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  790000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 3200000 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  810000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  820000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  830000, 3200000 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  840000, 3200000 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  850000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  875000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  885000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  905000, 3200000 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  915000, 3200000 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 3200000 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 3200000 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 3200000 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  760000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  770000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  780000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  790000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  810000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  820000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  830000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  840000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  850000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  875000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  885000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  905000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  915000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 707abef..0fe94d5 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -186,7 +186,7 @@
 #endif
 }
 
-static int apq8064_paddr_to_memtype(unsigned int paddr)
+static int apq8064_paddr_to_memtype(phys_addr_t paddr)
 {
 	return MEMTYPE_EBI1;
 }
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 6371b9d..3582914 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -25,6 +25,7 @@
 #include <linux/of_irq.h>
 #include <linux/memory.h>
 #include <linux/regulator/qpnp-regulator.h>
+#include <linux/msm_tsens.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
@@ -112,7 +113,7 @@
 		msm_clock_init(&msm8226_rumi_clock_init_data);
 	else
 		msm_clock_init(&msm8226_clock_init_data);
-
+	tsens_tm_init_driver();
 	msm_thermal_device_init();
 }
 
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 15d7679..4b435de 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -35,6 +35,48 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting lcd_en_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct gpiomux_setting lcd_en_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
+	{
+		.gpio = 41,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcd_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
+		},
+	},
+	{
+		.gpio = 7,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcd_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
 		.gpio      = 10,	/* BLSP1 QUP3 I2C_SDA */
@@ -74,6 +116,44 @@
 	},
 };
 
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+	{
+		.gpio = 23,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 25,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 26,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 27,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -85,4 +165,7 @@
 	}
 
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+	msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
 }
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 99db345..67334d5 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -24,6 +24,7 @@
 #include <linux/of_fdt.h>
 #include <linux/of_irq.h>
 #include <linux/memory.h>
+#include <linux/msm_tsens.h>
 #include <asm/mach/map.h>
 #include <asm/arch_timer.h>
 #include <asm/hardware/gic.h>
@@ -105,6 +106,7 @@
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
 	qpnp_regulator_init();
+	tsens_tm_init_driver();
 	msm_thermal_device_init();
 
 	if (of_board_is_rumi())
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 771e678..8be128c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -226,7 +226,7 @@
 #endif
 }
 
-static int msm8930_paddr_to_memtype(unsigned int paddr)
+static int msm8930_paddr_to_memtype(phys_addr_t paddr)
 {
 	return MEMTYPE_EBI1;
 }
@@ -957,7 +957,7 @@
 	},
 	{
 		ARRAY_SIZE(qseecom_enable_dfab_vectors),
-		qseecom_enable_sfpb_vectors,
+		qseecom_enable_dfab_vectors,
 	},
 	{
 		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index f3d8a2f..c5fc418 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -236,7 +236,7 @@
 #endif
 }
 
-static int msm8960_paddr_to_memtype(unsigned int paddr)
+static int msm8960_paddr_to_memtype(phys_addr_t paddr)
 {
 	return MEMTYPE_EBI1;
 }
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index e30d0ba..3b92171 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -743,7 +743,8 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct msm_gpiomux_config msm8974_pri_auxpcm_configs[] __initdata = {
+/* Primary AUXPCM port sharing GPIO lines with Primary MI2S */
+static struct msm_gpiomux_config msm8974_pri_pri_auxpcm_configs[] __initdata = {
 	{
 		.gpio = 65,
 		.settings = {
@@ -774,6 +775,38 @@
 	},
 };
 
+/* Primary AUXPCM port sharing GPIO lines with Tertiary MI2S */
+static struct msm_gpiomux_config msm8974_pri_ter_auxpcm_configs[] __initdata = {
+	{
+		.gpio = 74,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+		},
+	},
+	{
+		.gpio = 75,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+		},
+	},
+	{
+		.gpio = 76,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+		},
+	},
+	{
+		.gpio = 77,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+			[GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm8974_sec_auxpcm_configs[] __initdata = {
 	{
 		.gpio = 79,
@@ -1090,8 +1123,13 @@
 		msm_gpiomux_install(msm_mhl_configs,
 				    ARRAY_SIZE(msm_mhl_configs));
 
-	msm_gpiomux_install(msm8974_pri_auxpcm_configs,
-				 ARRAY_SIZE(msm8974_pri_auxpcm_configs));
+	if (of_board_is_liquid())
+		msm_gpiomux_install(msm8974_pri_ter_auxpcm_configs,
+				 ARRAY_SIZE(msm8974_pri_ter_auxpcm_configs));
+	else
+		msm_gpiomux_install(msm8974_pri_pri_auxpcm_configs,
+				 ARRAY_SIZE(msm8974_pri_pri_auxpcm_configs));
+
 	msm_gpiomux_install(msm8974_sec_auxpcm_configs,
 				 ARRAY_SIZE(msm8974_sec_auxpcm_configs));
 
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 9b69c8f..cfa1628 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -22,6 +22,7 @@
 #include <linux/memory.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/krait-regulator.h>
+#include <linux/msm_tsens.h>
 #include <linux/msm_thermal.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
@@ -59,7 +60,7 @@
 	},
 };
 
-static int msm8974_paddr_to_memtype(unsigned int paddr)
+static int msm8974_paddr_to_memtype(phys_addr_t paddr)
 {
 	return MEMTYPE_EBI1;
 }
@@ -101,6 +102,7 @@
 		msm_clock_init(&msm8974_rumi_clock_init_data);
 	else
 		msm_clock_init(&msm8974_clock_init_data);
+	tsens_tm_init_driver();
 	msm_thermal_device_init();
 }
 
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 923dc2a..3bb00bb 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -21,6 +21,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
 #include <linux/memory.h>
+#include <linux/msm_tsens.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
@@ -237,6 +238,7 @@
 	msm_spm_device_init();
 	msm_clock_init(&msm9625_clock_init_data);
 	msm9625_init_buses();
+	tsens_tm_init_driver();
 }
 
 void __init msm9625_init(void)
diff --git a/arch/arm/mach-msm/board-krypton-gpiomux.c b/arch/arm/mach-msm/board-krypton-gpiomux.c
new file mode 100644
index 0000000..3d86ba7
--- /dev/null
+++ b/arch/arm/mach-msm/board-krypton-gpiomux.c
@@ -0,0 +1,52 @@
+/* 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/ioport.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+static struct gpiomux_setting gpio_uart_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+	{
+		.gpio      = 8,	       /* BLSP1 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+	{
+		.gpio      = 9,	       /* BLSP1 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+};
+
+void __init msmkrypton_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init_dt();
+	if (rc) {
+		pr_err("%s failed %d\n", __func__, rc);
+		return;
+	}
+
+	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
new file mode 100644
index 0000000..aada3b0
--- /dev/null
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -0,0 +1,84 @@
+/* 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/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msmkrypton_add_drivers(void)
+{
+	msm_smd_init();
+	msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init msmkrypton_map_io(void)
+{
+	msm_map_msmkrypton_io();
+}
+
+void __init msmkrypton_init(void)
+{
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+
+	msmkrypton_init_gpiomux();
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	msmkrypton_add_drivers();
+}
+
+static const char *msmkrypton_dt_match[] __initconst = {
+	"qcom,msmkrypton",
+	NULL
+};
+
+DT_MACHINE_START(MSMKRYPTON_DT, "Qualcomm MSM Krypton (Flattened Device Tree)")
+	.map_io = msmkrypton_map_io,
+	.init_irq = msm_dt_init_irq,
+	.init_machine = msmkrypton_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_dt_timer,
+	.dt_compat = msmkrypton_dt_match,
+	.restart = msm_restart,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 6b98393..0e1c03e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5558,7 +5558,7 @@
 	reserve_rtb_memory();
 }
 
-static int msm8x60_paddr_to_memtype(unsigned int paddr)
+static int msm8x60_paddr_to_memtype(phys_addr_t paddr)
 {
 	if (paddr >= 0x40000000 && paddr < 0x60000000)
 		return MEMTYPE_EBI1;
diff --git a/arch/arm/mach-msm/board-zinc.c b/arch/arm/mach-msm/board-zinc.c
index fa19e39..444444f 100644
--- a/arch/arm/mach-msm/board-zinc.c
+++ b/arch/arm/mach-msm/board-zinc.c
@@ -43,7 +43,7 @@
 	},
 };
 
-static int msmzinc_paddr_to_memtype(unsigned int paddr)
+static int msmzinc_paddr_to_memtype(phys_addr_t paddr)
 {
 	return MEMTYPE_EBI1;
 }
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 80907c8..5f9eafd 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2776,6 +2776,7 @@
 	},
 	.base = &virt_bases[APCS_PLL_BASE],
 	.c = {
+		.parent = &xo_a_clk.c,
 		.dbg_name = "a7sspll",
 		.ops = &clk_ops_sr2_pll,
 		.vdd_class = &vdd_sr2_pll,
@@ -3529,17 +3530,6 @@
 		panic("clock-8226: Unable to get the vdd_sr2_dig regulator!");
 
 	/*
-	 * These regulators are used at boot. Ensure they stay on
-	 * while the clock framework comes online.
-	 */
-	vote_vdd_level(&vdd_sr2_pll, VDD_SR2_PLL_TUR);
-	regulator_enable(vdd_sr2_pll.regulator[0]);
-	regulator_enable(vdd_sr2_pll.regulator[1]);
-
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	regulator_enable(vdd_dig.regulator[0]);
-
-	/*
 	 * Hold an active set vote at a rate of 40MHz for the MMSS NOC AHB
 	 * source. Sleep set vote is 0.
 	 * RPM will also turn on gcc_mmss_noc_cfg_ahb_clk, which is needed to
@@ -3561,17 +3551,9 @@
 	mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
 }
 
-static int __init msm8226_clock_late_init(void)
-{
-	unvote_vdd_level(&vdd_sr2_pll, VDD_SR2_PLL_TUR);
-	unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	return 0;
-}
-
 struct clock_init_data msm8226_clock_init_data __initdata = {
 	.table = msm_clocks_8226,
 	.size = ARRAY_SIZE(msm_clocks_8226),
 	.pre_init = msm8226_clock_pre_init,
 	.post_init = msm8226_clock_post_init,
-	.late_init = msm8226_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 768efe7..4a716fc 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -564,6 +564,7 @@
 	},
 	.base = &virt_bases[APCS_PLL_BASE],
 	.c = {
+		.parent = &gcc_xo_a_clk_src.c,
 		.dbg_name = "a7sspll",
 		.ops = &clk_ops_sr2_pll,
 		.vdd_class = &vdd_sr2_pll,
@@ -2782,12 +2783,16 @@
 	CLK_LOOKUP("measure_clk", apc3_m_clk, ""),
 	CLK_LOOKUP("measure_clk",   l2_m_clk, ""),
 
+	CLK_LOOKUP("xo",   gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("rf_clk",       cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
+
 	CLK_LOOKUP("iface_clk", mdp_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("core_clk", mdp_axi_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("lcdc_clk", mdp_lcdc_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("dsi_clk", mdp_dsi_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("iface_clk", dsi_ahb_clk.c, "fdd00000.qcom,mdss_dsi"),
-	CLK_LOOKUP("core_clk", dsi_clk.c, "fdd00000.qcom,mdss_dsi"),
+	CLK_LOOKUP("dsi_clk", dsi_clk.c, "fdd00000.qcom,mdss_dsi"),
 	CLK_LOOKUP("byte_clk", dsi_byte_clk.c, "fdd00000.qcom,mdss_dsi"),
 	CLK_LOOKUP("esc_clk", dsi_esc_clk.c, "fdd00000.qcom,mdss_dsi"),
 	CLK_LOOKUP("pixel_clk", dsi_pclk_clk.c, "fdd00000.qcom,mdss_dsi"),
@@ -2966,19 +2971,6 @@
 	if (IS_ERR(vdd_sr2_pll.regulator[1]))
 		panic("clock-8610: Unable to get the vdd_sr2_dig regulator!");
 
-	vote_vdd_level(&vdd_sr2_pll, VDD_SR2_PLL_TUR);
-	regulator_enable(vdd_sr2_pll.regulator[0]);
-	regulator_enable(vdd_sr2_pll.regulator[1]);
-
-	/*
-	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
-	 * until late_init. This may not be necessary with clock handoff;
-	 * Investigate this code on a real non-simulator target to determine
-	 * its necessity.
-	 */
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	regulator_enable(vdd_dig.regulator[0]);
-
 	enable_rpm_scaling();
 
 	/* Enable a clock to allow access to MMSS clock registers */
@@ -2995,17 +2987,9 @@
 	clk_prepare_enable(&mmss_s0_axi_clk.c);
 }
 
-static int __init msm8610_clock_late_init(void)
-{
-	unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	unvote_vdd_level(&vdd_sr2_pll, VDD_SR2_PLL_TUR);
-	return 0;
-}
-
 struct clock_init_data msm8610_clock_init_data __initdata = {
 	.table = msm_clocks_8610,
 	.size = ARRAY_SIZE(msm_clocks_8610),
 	.pre_init = msm8610_clock_pre_init,
 	.post_init = msm8610_clock_post_init,
-	.late_init = msm8610_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index aefaa5c..509443d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6740,8 +6740,6 @@
 	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
 		prng_clk.freq_tbl = clk_tbl_prng_64;
 
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-
 	clk_ops_local_pll.enable = sr_pll_clk_enable;
 }
 
@@ -6852,7 +6850,7 @@
 	if (WARN(rc, "cfpb_a_clk not enabled (%d)\n", rc))
 		return rc;
 
-	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+	return 0;
 }
 
 struct clock_init_data msm8960_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index e6874b7..c42da92 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1405,7 +1405,14 @@
 };
 
 static struct clk_freq_tbl ftbl_gcc_gp_clk[] = {
-	F(19200000,  cxo,  1,   0,   0),
+	F( 4800000,   cxo,  4,  0,   0),
+	F( 6000000, gpll0, 10,  1,  10),
+	F( 6750000, gpll0,  1,  1,  89),
+	F( 8000000, gpll0, 15,  1,   5),
+	F( 9600000,   cxo,  2,  0,   0),
+	F(16000000, gpll0,  1,  2,  75),
+	F(19200000,   cxo,  1,  0,   0),
+	F(24000000, gpll0,  5,  1,   5),
 	F_END
 };
 
@@ -5107,6 +5114,7 @@
 	CLK_LOOKUP("bus_clk",  venus0_axi_clk.c, "fdc00000.qcom,vidc"),
 	CLK_LOOKUP("mem_clk",  venus0_ocmemnoc_clk.c, "fdc00000.qcom,vidc"),
 
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4024.qcom,gdsc"),
 
 	/* LPASS clocks */
 	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
@@ -5487,15 +5495,6 @@
 	if (IS_ERR(vdd_dig.regulator[0]))
 		panic("clock-8974: Unable to get the vdd_dig regulator!");
 
-	/*
-	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
-	 * until late_init. This may not be necessary with clock handoff;
-	 * Investigate this code on a real non-simulator target to determine
-	 * its necessity.
-	 */
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	regulator_enable(vdd_dig.regulator[0]);
-
 	enable_rpm_scaling();
 
 	reg_init();
@@ -5532,11 +5531,6 @@
 	mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
 }
 
-static int __init msm8974_clock_late_init(void)
-{
-	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-}
-
 static void __init msm8974_rumi_clock_pre_init(void)
 {
 	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5552,15 +5546,6 @@
 	vdd_dig.regulator[0] = regulator_get(NULL, "vdd_dig");
 	if (IS_ERR(vdd_dig.regulator[0]))
 		panic("clock-8974: Unable to get the vdd_dig regulator!");
-
-	/*
-	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
-	 * until late_init. This may not be necessary with clock handoff;
-	 * Investigate this code on a real non-simulator target to determine
-	 * its necessity.
-	 */
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	regulator_enable(vdd_dig.regulator[0]);
 }
 
 struct clock_init_data msm8974_clock_init_data __initdata = {
@@ -5568,7 +5553,6 @@
 	.size = ARRAY_SIZE(msm_clocks_8974),
 	.pre_init = msm8974_clock_pre_init,
 	.post_init = msm8974_clock_post_init,
-	.late_init = msm8974_clock_late_init,
 };
 
 struct clock_init_data msm8974_rumi_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index d0b4a32..5d55966 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3777,8 +3777,6 @@
 
 static void __init msm8660_clock_pre_init(void)
 {
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-
 	/* Setup MM_PLL2 (PLL3), but turn it off. Rate set by set_rate_tv(). */
 	rmwreg(0, MM_PLL2_MODE_REG, BIT(0)); /* Disable output */
 	/* Set ref, bypass, assert reset, disable output, disable test mode */
@@ -3900,7 +3898,7 @@
 	if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
 		return rc;
 
-	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+	return 0;
 }
 
 struct clock_init_data msm8x60_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index d6ae4335..6b218a1 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1754,8 +1754,6 @@
 {
 	u32 regval, is_pll_enabled, pll9_lval;
 
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-
 	clk_ops_local_pll.enable = sr_pll_clk_enable;
 
 	/* Enable PDM CXO source. */
@@ -1831,15 +1829,9 @@
 	clk_disable_unprepare(&pdm_clk.c);
 }
 
-static int __init msm9615_clock_late_init(void)
-{
-	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-}
-
 struct clock_init_data msm9615_clock_init_data __initdata = {
 	.table = msm_clocks_9615,
 	.size = ARRAY_SIZE(msm_clocks_9615),
 	.pre_init = msm9615_clock_pre_init,
 	.post_init = msm9615_clock_post_init,
-	.late_init = msm9615_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 6817c6c..0d97401 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -411,6 +411,7 @@
 	},
 	.base = &virt_bases[APCS_PLL_BASE],
 	.c = {
+		.parent = &cxo_a_clk_src.c,
 		.dbg_name = "apcspll_clk_src",
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(apcspll_clk_src.c),
@@ -2089,9 +2090,6 @@
 	if (IS_ERR(vdd_dig.regulator[0]))
 		panic("clock-9625: Unable to get the vdd_dig regulator!");
 
-	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-	regulator_enable(vdd_dig.regulator[0]);
-
 	enable_rpm_scaling();
 
 	reg_init();
@@ -2107,15 +2105,9 @@
 			measure_mux_common, sizeof(measure_mux_common));
 }
 
-static int __init msm9625_clock_late_init(void)
-{
-	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
-}
-
 struct clock_init_data msm9625_clock_init_data __initdata = {
 	.table = msm_clocks_9625,
 	.size = ARRAY_SIZE(msm_clocks_9625),
 	.pre_init = msm9625_clock_pre_init,
 	.post_init = msm9625_clock_post_init,
-	.late_init = msm9625_clock_late_init,
 };
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 5da1663..0b8240c 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -756,10 +756,10 @@
 	spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
 	reg_val = readl_relaxed(b->retain_reg);
 	switch (flags) {
-	case CLKFLAG_RETAIN:
+	case CLKFLAG_RETAIN_MEM:
 		reg_val |= b->retain_mask;
 		break;
-	case CLKFLAG_NORETAIN:
+	case CLKFLAG_NORETAIN_MEM:
 		reg_val &= ~b->retain_mask;
 		break;
 	default:
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 8bdc496..8c2121f 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -570,6 +570,40 @@
 	return __branch_clk_reset(BCR_REG(branch), action);
 }
 
+static int branch_clk_set_flags(struct clk *c, unsigned flags)
+{
+	u32 cbcr_val;
+	unsigned long irq_flags;
+	struct branch_clk *branch = to_branch_clk(c);
+	int ret = 0;
+
+	spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
+	cbcr_val = readl_relaxed(CBCR_REG(branch));
+	switch (flags) {
+	case CLKFLAG_RETAIN_PERIPH:
+		cbcr_val |= BIT(13);
+		break;
+	case CLKFLAG_NORETAIN_PERIPH:
+		cbcr_val &= ~BIT(13);
+		break;
+	case CLKFLAG_RETAIN_MEM:
+		cbcr_val |= BIT(14);
+		break;
+	case CLKFLAG_NORETAIN_MEM:
+		cbcr_val &= ~BIT(14);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	writel_relaxed(cbcr_val, CBCR_REG(branch));
+	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
+
+	/* Make sure write is issued before returning. */
+	mb();
+
+	return ret;
+}
+
 /*
  * Voteable clock functions
  */
@@ -824,6 +858,7 @@
 	.list_rate = branch_clk_list_rate,
 	.round_rate = branch_clk_round_rate,
 	.reset = branch_clk_reset,
+	.set_flags = branch_clk_set_flags,
 	.handoff = branch_clk_handoff,
 };
 
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 9b34465..044fc2c 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -33,6 +33,12 @@
 };
 static LIST_HEAD(handoff_list);
 
+struct handoff_vdd {
+	struct list_head list;
+	struct clk_vdd_class *vdd_class;
+};
+static LIST_HEAD(handoff_vdd_list);
+
 /* Find the voltage level required for a given rate. */
 int find_vdd_level(struct clk *clk, unsigned long rate)
 {
@@ -159,7 +165,7 @@
 	unvote_vdd_level(clk->vdd_class, level);
 }
 
-/* Returns true if the rate is valid without voting for it */
+/* Check if the rate is within the voltage limits of the clock. */
 static bool is_rate_valid(struct clk *clk, unsigned long rate)
 {
 	int level;
@@ -171,6 +177,92 @@
 	return level >= 0;
 }
 
+/**
+ * __clk_pre_reparent() - Set up the new parent before switching to it and
+ * prevent the enable state of the child clock from changing.
+ * @c: The child clock that's going to switch parents
+ * @new: The new parent that the child clock is going to switch to
+ * @flags: Pointer to scratch space to save spinlock flags
+ *
+ * Cannot be called from atomic context.
+ *
+ * Use this API to set up the @new parent clock to be able to support the
+ * current prepare and enable state of the child clock @c. Once the parent is
+ * set up, the child clock can safely switch to it.
+ *
+ * The caller shall grab the prepare_lock of clock @c before calling this API
+ * and only release it after calling __clk_post_reparent() for clock @c (or
+ * if this API fails). This is necessary to prevent the prepare state of the
+ * child clock @c from changing while the reparenting is in progress. Since
+ * this API takes care of grabbing the enable lock of @c, only atomic
+ * operation are allowed between calls to __clk_pre_reparent and
+ * __clk_post_reparent()
+ *
+ * The scratch space pointed to by @flags should not be altered before
+ * calling __clk_post_reparent() for clock @c.
+ *
+ * See also: __clk_post_reparent()
+ */
+int __clk_pre_reparent(struct clk *c, struct clk *new, unsigned long *flags)
+{
+	int rc;
+
+	if (c->prepare_count) {
+		rc = clk_prepare(new);
+		if (rc)
+			return rc;
+	}
+
+	spin_lock_irqsave(&c->lock, *flags);
+	if (c->count) {
+		rc = clk_enable(new);
+		if (rc) {
+			spin_unlock_irqrestore(&c->lock, *flags);
+			clk_unprepare(new);
+			return rc;
+		}
+	}
+	return 0;
+}
+
+/**
+ * __clk_post_reparent() - Release requirements on old parent after switching
+ * away from it and allow changes to the child clock's enable state.
+ * @c:   The child clock that switched parents
+ * @old: The old parent that the child clock switched away from or the new
+ *	 parent of a failed reparent attempt.
+ * @flags: Pointer to scratch space where spinlock flags were saved
+ *
+ * Cannot be called from atomic context.
+ *
+ * This API works in tandem with __clk_pre_reparent. Use this API to
+ * - Remove prepare and enable requirements from the @old parent after
+ *   switching away from it
+ * - Or, undo the effects of __clk_pre_reparent() after a failed attempt to
+ *   change parents
+ *
+ * The caller shall release the prepare_lock of @c that was grabbed before
+ * calling __clk_pre_reparent() only after this API is called (or if
+ * __clk_pre_reparent() fails). This is necessary to prevent the prepare
+ * state of the child clock @c from changing while the reparenting is in
+ * progress. Since this API releases the enable lock of @c, the limit to
+ * atomic operations set by __clk_pre_reparent() is no longer present.
+ *
+ * The scratch space pointed to by @flags shall not be altered since the call
+ * to  __clk_pre_reparent() for clock @c.
+ *
+ * See also: __clk_pre_reparent()
+ */
+void __clk_post_reparent(struct clk *c, struct clk *old, unsigned long *flags)
+{
+	if (c->count)
+		clk_disable(old);
+	spin_unlock_irqrestore(&c->lock, *flags);
+
+	if (c->prepare_count)
+		clk_unprepare(old);
+}
+
 int clk_prepare(struct clk *clk)
 {
 	int ret = 0;
@@ -357,6 +449,9 @@
 	if (!clk->ops->set_rate)
 		return -ENOSYS;
 
+	if (!is_rate_valid(clk, rate))
+		return -EINVAL;
+
 	mutex_lock(&clk->prepare_lock);
 
 	/* Return early if the rate isn't going to change */
@@ -364,31 +459,32 @@
 		goto out;
 
 	trace_clock_set_rate(name, rate, raw_smp_processor_id());
+
+	start_rate = clk->rate;
+
+	/* Enforce vdd requirements for target frequency. */
 	if (clk->prepare_count) {
-		start_rate = clk->rate;
-		/* Enforce vdd requirements for target frequency. */
 		rc = vote_rate_vdd(clk, rate);
 		if (rc)
 			goto out;
-		rc = clk->ops->set_rate(clk, rate);
-		if (rc)
-			goto err_set_rate;
-		/* Release vdd requirements for starting frequency. */
-		unvote_rate_vdd(clk, start_rate);
-	} else if (is_rate_valid(clk, rate)) {
-		rc = clk->ops->set_rate(clk, rate);
-	} else {
-		rc = -EINVAL;
 	}
 
-	if (!rc)
-		clk->rate = rate;
+	rc = clk->ops->set_rate(clk, rate);
+	if (rc)
+		goto err_set_rate;
+	clk->rate = rate;
+
+	/* Release vdd requirements for starting frequency. */
+	if (clk->prepare_count)
+		unvote_rate_vdd(clk, start_rate);
+
 out:
 	mutex_unlock(&clk->prepare_lock);
 	return rc;
 
 err_set_rate:
-	unvote_rate_vdd(clk, rate);
+	if (clk->prepare_count)
+		unvote_rate_vdd(clk, rate);
 	goto out;
 }
 EXPORT_SYMBOL(clk_set_rate);
@@ -498,6 +594,38 @@
 }
 EXPORT_SYMBOL(msm_clock_register);
 
+
+static void vdd_class_init(struct clk_vdd_class *vdd)
+{
+	struct handoff_vdd *v;
+	int i;
+
+	if (!vdd)
+		return;
+
+	list_for_each_entry(v, &handoff_vdd_list, list) {
+		if (v->vdd_class == vdd)
+			return;
+	}
+
+	pr_debug("voting for vdd_class %s\n", vdd->class_name);
+	if (vote_vdd_level(vdd, vdd->num_levels - 1))
+		pr_err("failed to vote for %s\n", vdd->class_name);
+
+	for (i = 0; i < vdd->num_regulators; i++)
+		regulator_enable(vdd->regulator[i]);
+
+	v = kmalloc(sizeof(*v), GFP_KERNEL);
+	if (!v) {
+		pr_err("Unable to kmalloc. %s will be stuck at max.\n",
+			vdd->class_name);
+		return;
+	}
+
+	v->vdd_class = vdd;
+	list_add_tail(&v->list, &handoff_vdd_list);
+}
+
 static int __init __handoff_clk(struct clk *clk)
 {
 	enum handoff state = HANDOFF_DISABLED_CLK;
@@ -603,6 +731,16 @@
 	init_sibling_lists(clock_tbl, num_clocks);
 
 	/*
+	 * Enable regulators and temporarily set them up at maximum voltage.
+	 * Once all the clocks have made their respective vote, remove this
+	 * temporary vote. The removing of the temporary vote is done at
+	 * late_init, by which time we assume all the clocks would have been
+	 * handed off.
+	 */
+	for (n = 0; n < num_clocks; n++)
+		vdd_class_init(clock_tbl[n].clk->vdd_class);
+
+	/*
 	 * Detect and preserve initial clock state until clock_late_init() or
 	 * a driver explicitly changes it, whichever is first.
 	 */
@@ -623,8 +761,12 @@
 static int __init clock_late_init(void)
 {
 	struct handoff_clk *h, *h_temp;
+	struct handoff_vdd *v, *v_temp;
 	int ret = 0;
 
+	if (clk_init_data->late_init)
+		ret = clk_init_data->late_init();
+
 	pr_info("%s: Removing enables held for handed-off clocks\n", __func__);
 	list_for_each_entry_safe(h, h_temp, &handoff_list, list) {
 		clk_disable_unprepare(h->clk);
@@ -632,8 +774,12 @@
 		kfree(h);
 	}
 
-	if (clk_init_data->late_init)
-		ret = clk_init_data->late_init();
+	list_for_each_entry_safe(v, v_temp, &handoff_vdd_list, list) {
+		unvote_vdd_level(v->vdd_class, v->vdd_class->num_levels - 1);
+		list_del(&v->list);
+		kfree(v);
+	}
+
 	return ret;
 }
 late_initcall(clock_late_init);
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index d5fe866..76ad9b8 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -206,7 +206,7 @@
 	}
 
 	/* Prevent core memory from collapsing when its clock is gated. */
-	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN_MEM);
 
 	/* Return clocks to their state before this function. */
 	restore_clocks(fs);
@@ -238,7 +238,7 @@
 		return rc;
 
 	/* Allow core memory to collapse when its clock is gated. */
-	clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN);
+	clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN_MEM);
 
 	/* Halt all bus ports in the power domain. */
 	if (fs->bus_port0) {
@@ -292,7 +292,7 @@
 err_port2_halt:
 	msm_bus_axi_portunhalt(fs->bus_port0);
 err:
-	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN_MEM);
 	restore_clocks(fs);
 	return rc;
 }
@@ -360,7 +360,7 @@
 	clk_prepare_enable(fs->core_clk);
 
 	/* Prevent core memory from collapsing when its clock is gated. */
-	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN_MEM);
 
 	/* Return clocks to their state before this function. */
 	restore_clocks(fs);
@@ -390,7 +390,7 @@
 		return rc;
 
 	/* Allow core memory to collapse when its clock is gated. */
-	clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN);
+	clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN_MEM);
 
 	/* Halt all bus ports in the power domain. */
 	if (fs->bus_port0) {
@@ -436,7 +436,7 @@
 	return 0;
 
 err:
-	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN_MEM);
 	restore_clocks(fs);
 	return rc;
 }
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index e5b9d93..6665d66 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,8 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
 
 #define PWR_ON_MASK		BIT(31)
 #define EN_REST_WAIT_MASK	(0xF << 20)
@@ -42,6 +44,7 @@
 	struct regulator_dev	*rdev;
 	struct regulator_desc	rdesc;
 	void __iomem		*gdscr;
+	struct clk		*core_clk;
 };
 
 static int gdsc_is_enabled(struct regulator_dev *rdev)
@@ -108,6 +111,7 @@
 	struct resource *res;
 	struct gdsc *sc;
 	uint32_t regval;
+	bool retain_mems;
 	int ret;
 
 	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
@@ -151,6 +155,16 @@
 	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
 	writel_relaxed(regval, sc->gdscr);
 
+	retain_mems = of_property_read_bool(pdev->dev.of_node,
+					    "qcom,retain-mems");
+	if (retain_mems) {
+		sc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+		if (IS_ERR(sc->core_clk))
+			return PTR_ERR(sc->core_clk);
+		clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_MEM);
+		clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_PERIPH);
+	}
+
 	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
 				      pdev->dev.of_node);
 	if (IS_ERR(sc->rdev)) {
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 35257b2..72f5051 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -601,6 +601,7 @@
 void msm_map_fsm9xxx_io(void);
 void msm_map_8974_io(void);
 void msm_map_zinc_io(void);
+void msm_map_msmkrypton_io(void);
 void msm_map_msm8625_io(void);
 void msm_map_msm9625_io(void);
 void msm_init_irq(void);
@@ -611,6 +612,7 @@
 void msm_8974_init_gpiomux(void);
 void msmzinc_init_gpiomux(void);
 void msm9625_init_gpiomux(void);
+void msmkrypton_init_gpiomux(void);
 void msm_map_mpq8092_io(void);
 void mpq8092_init_gpiomux(void);
 void msm_map_msm8226_io(void);
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 528e9d5..2a33228 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -156,6 +156,8 @@
 
 int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
 int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+int __clk_pre_reparent(struct clk *c, struct clk *new, unsigned long *flags);
+void __clk_post_reparent(struct clk *c, struct clk *old, unsigned long *flags);
 
 /* Register clocks with the MSM clock driver */
 int msm_clock_register(struct clk_lookup *table, size_t size);
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index 1191bb7..1809456 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -16,8 +16,10 @@
 #define CLKFLAG_NOINVERT		0x00000002
 #define CLKFLAG_NONEST			0x00000004
 #define CLKFLAG_NORESET			0x00000008
-#define CLKFLAG_RETAIN			0x00000040
-#define CLKFLAG_NORETAIN		0x00000080
+#define CLKFLAG_RETAIN_PERIPH		0x00000010
+#define CLKFLAG_NORETAIN_PERIPH		0x00000020
+#define CLKFLAG_RETAIN_MEM		0x00000040
+#define CLKFLAG_NORETAIN_MEM		0x00000080
 #define CLKFLAG_SKIP_HANDOFF		0x00000100
 #define CLKFLAG_MIN			0x00000400
 #define CLKFLAG_MAX			0x00000800
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h b/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h
new file mode 100644
index 0000000..a8b9da5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-krypton.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_MSMKRYPTON_H
+#define __ASM_ARCH_MSM_IOMAP_MSMKRYPTON_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSMKRYPTON_SHARED_RAM_PHYS		0x00000000
+
+#define MSMKRYPTON_TLMM_PHYS			0xFD510000
+#define MSMKRYPTON_TLMM_SIZE			SZ_16K
+
+#define MSMKRYPTON_MPM2_PSHOLD_PHYS		0xFC4AB000
+#define MSMKRYPTON_MPM2_PSHOLD_SIZE		SZ_4K
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index d3706cd..f27eb36 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -134,6 +134,7 @@
 #include "msm_iomap-8092.h"
 #include "msm_iomap-8226.h"
 #include "msm_iomap-8610.h"
+#include "msm_iomap-krypton.h"
 
 #endif
 
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 264dad5..3bf05e6 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -45,9 +45,9 @@
 #define MEMTYPE_FLAGS_1M_ALIGN	0x2
 
 struct memtype_reserve {
-	unsigned long start;
-	unsigned long size;
-	unsigned long limit;
+	phys_addr_t start;
+	phys_addr_t size;
+	phys_addr_t limit;
 	int flags;
 };
 
@@ -55,7 +55,7 @@
 	struct memtype_reserve *memtype_reserve_table;
 	void (*calculate_reserve_sizes)(void);
 	void (*reserve_fixed_area)(unsigned long);
-	int (*paddr_to_memtype)(unsigned int);
+	int (*paddr_to_memtype)(phys_addr_t);
 	unsigned long low_unstable_address;
 	unsigned long max_unstable_size;
 	unsigned long bank_size;
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/include/mach/ramdump.h
similarity index 100%
rename from arch/arm/mach-msm/ramdump.h
rename to arch/arm/mach-msm/include/mach/ramdump.h
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index b898fe8..7c9882e 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -48,6 +48,8 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mpq8092")
 #define early_machine_is_msmzinc()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmzinc")
+#define early_machine_is_msmkrypton()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmkrypton")
 #else
 #define of_board_is_sim()		0
 #define of_board_is_rumi()		0
@@ -62,6 +64,7 @@
 #define early_machine_is_msm8610()	0
 #define early_machine_is_mpq8092()	0
 #define early_machine_is_msmzinc()	0
+#define early_machine_is_msmkrypton()	0
 #endif
 
 #define PLATFORM_SUBTYPE_SGLTE	6
@@ -100,6 +103,7 @@
 	MSM_CPU_8610,
 	MSM_CPU_8625Q,
 	MSM_CPU_ZINC,
+	MSM_CPU_KRYPTON,
 };
 
 enum pmic_model {
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 25cbc87..c5ad35d 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -258,6 +258,7 @@
 enum sps_callback_case {
 	SPS_CALLBACK_BAM_ERROR_IRQ = 1,     /* BAM ERROR IRQ */
 	SPS_CALLBACK_BAM_HRESP_ERR_IRQ,	    /* Erroneous HResponse */
+	SPS_CALLBACK_BAM_TIMER_IRQ,	    /* Inactivity timer */
 };
 
 /*
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 19c7acd..ecac4a5 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -507,6 +507,25 @@
 }
 #endif /* CONFIG_ARCH_MSM9625 */
 
+#ifdef CONFIG_ARCH_MSMKRYPTON
+static struct map_desc msmkrypton_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(TLMM, MSMKRYPTON),
+	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSMKRYPTON),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+};
+
+void __init msm_map_msmkrypton_io(void)
+{
+	msm_shared_ram_phys = MSMKRYPTON_SHARED_RAM_PHYS;
+	msm_map_io(msmkrypton_io_desc, ARRAY_SIZE(msmkrypton_io_desc));
+	of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_MSMKRYPTON */
+
 #ifdef CONFIG_ARCH_MPQ8092
 static struct map_desc mpq8092_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MPQ8092),
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 953f941d..b931ee6 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -61,9 +61,7 @@
 #define PMIC_VOLTAGE_MAX		1355000
 #define LV_RANGE_STEP			5000
 
-#define LOAD_PER_PHASE			3200000
-
-#define CORE_VOLTAGE_MIN		900000
+#define CORE_VOLTAGE_BOOTUP		900000
 
 #define KRAIT_LDO_VOLTAGE_MIN		465000
 #define KRAIT_LDO_VOLTAGE_OFFSET	465000
@@ -146,7 +144,10 @@
  *				regulator's callback functions to prevent
  *				simultaneous updates to the pmic's phase
  *				voltage.
- * @apcs_gcc_base		virtual address of the APCS GCC registers
+ * @apcs_gcc_base:		virtual address of the APCS GCC registers
+ * @manage_phases:		begin phase control
+ * @pfm_threshold:		the sum of coefficients below which PFM can be
+ *				enabled
  */
 struct pmic_gang_vreg {
 	const char		*name;
@@ -159,6 +160,8 @@
 	bool			retention_enabled;
 	bool			use_phase_switching;
 	void __iomem		*apcs_gcc_base;
+	bool			manage_phases;
+	int			pfm_threshold;
 };
 
 static struct pmic_gang_vreg *the_gang;
@@ -168,6 +171,9 @@
 	LDO_MODE = REGULATOR_MODE_IDLE,
 };
 
+#define WAIT_FOR_LOAD		0x2
+#define WAIT_FOR_VOLTAGE	0x1
+
 struct krait_power_vreg {
 	struct list_head		link;
 	struct regulator_desc		desc;
@@ -175,7 +181,7 @@
 	const char			*name;
 	struct pmic_gang_vreg		*pvreg;
 	int				uV;
-	int				load_uA;
+	int				load;
 	enum krait_supply_mode		mode;
 	void __iomem			*reg_base;
 	void __iomem			*mdd_base;
@@ -185,7 +191,10 @@
 	int				ldo_threshold_uV;
 	int				ldo_delta_uV;
 	int				cpu_num;
+	int				coeff1;
+	int				coeff2;
 	bool				online;
+	int				online_at_probe;
 };
 
 DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -293,6 +302,229 @@
 	return 0;
 }
 
+#define COEFF2_UV_THRESHOLD 850000
+static int get_coeff2(int krait_uV)
+{
+	int coeff2 = 0;
+	int krait_mV = krait_uV / 1000;
+
+	if (krait_uV <= COEFF2_UV_THRESHOLD)
+		coeff2 = (612229 * krait_mV) / 1000 - 211258;
+	else
+		coeff2 = (892564 * krait_mV) / 1000 - 449543;
+
+	return  coeff2;
+}
+
+static int get_coeff1(int actual_uV, int requested_uV, int load)
+{
+	int ratio = actual_uV * 1000 / requested_uV;
+	int coeff1 = 330 * load + (load * 673 * ratio / 1000);
+
+	return coeff1;
+}
+
+static int get_coeff_total(struct krait_power_vreg *from)
+{
+	int coeff_total = 0;
+	struct krait_power_vreg *kvreg;
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		if (!kvreg->online)
+			continue;
+
+		if (kvreg->mode == LDO_MODE) {
+			kvreg->coeff1 =
+				get_coeff1(kvreg->uV - kvreg->ldo_delta_uV,
+							kvreg->uV, kvreg->load);
+			kvreg->coeff2 =
+				get_coeff2(kvreg->uV - kvreg->ldo_delta_uV);
+		} else {
+			kvreg->coeff1 =
+				get_coeff1(pvreg->pmic_vmax_uV,
+							kvreg->uV, kvreg->load);
+			kvreg->coeff2 = get_coeff2(pvreg->pmic_vmax_uV);
+		}
+		coeff_total += kvreg->coeff1 + kvreg->coeff2;
+	}
+
+	return coeff_total;
+}
+
+static int set_pmic_gang_phases(struct pmic_gang_vreg *pvreg, int phase_count)
+{
+	pr_debug("programming phase_count = %d\n", phase_count);
+	if (pvreg->use_phase_switching)
+		/*
+		 * note the PMIC sets the phase count to one more than
+		 * the value in the register - hence subtract 1 from it
+		 */
+		return msm_spm_apcs_set_phase(phase_count - 1);
+	else
+		return 0;
+}
+
+static int num_online(struct pmic_gang_vreg *pvreg)
+{
+	int online_total = 0;
+	struct krait_power_vreg *kvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		if (kvreg->online)
+			online_total++;
+	}
+	return online_total;
+}
+
+static bool enable_phase_management(struct pmic_gang_vreg *pvreg)
+{
+	struct krait_power_vreg *kvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		pr_debug("%s online_at_probe:0x%x\n", kvreg->name,
+							kvreg->online_at_probe);
+		if (kvreg->online_at_probe)
+			return false;
+	}
+	return true;
+}
+
+#define PMIC_FTS_MODE_PFM	0x00
+#define PMIC_FTS_MODE_PWM	0x80
+#define ONE_PHASE_COEFF		1000000
+#define TWO_PHASE_COEFF		2000000
+
+#define PHASE_SETTLING_TIME_US		10
+static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
+				int coeff_total)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+	int phase_count;
+	int rc = 0;
+	int n_online = num_online(pvreg);
+
+	if (pvreg->manage_phases == false) {
+		if (enable_phase_management(pvreg))
+			pvreg->manage_phases = true;
+		else
+			return 0;
+	}
+
+	/* First check if the coeff is low for PFM mode */
+	if (coeff_total < pvreg->pfm_threshold && n_online == 1) {
+		if (!pvreg->pfm_mode) {
+			rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
+			if (rc) {
+				pr_err("%s PFM en failed coeff_t %d rc = %d\n",
+					from->name, coeff_total, rc);
+				return rc;
+			} else {
+				pvreg->pfm_mode = true;
+			}
+		}
+		return rc;
+	}
+
+	/* coeff is high switch to PWM mode before changing phases */
+	if (pvreg->pfm_mode) {
+		rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PWM);
+		if (rc) {
+			pr_err("%s PFM exit failed load %d rc = %d\n",
+				from->name, coeff_total, rc);
+			return rc;
+		} else {
+			pvreg->pfm_mode = false;
+		}
+	}
+
+	/* calculate phases */
+	if (coeff_total < ONE_PHASE_COEFF)
+		phase_count = 1;
+	else if (coeff_total < TWO_PHASE_COEFF)
+		phase_count = 2;
+	else
+		phase_count = 4;
+
+	/* don't increase the phase count higher than number of online cpus */
+	if (phase_count > n_online)
+		phase_count = n_online;
+
+	if (phase_count != pvreg->pmic_phase_count) {
+		rc = set_pmic_gang_phases(pvreg, phase_count);
+		if (rc < 0) {
+			pr_err("%s failed set phase %d rc = %d\n",
+				from->name, phase_count, rc);
+			return rc;
+		}
+
+		/* complete the writes before the delay */
+		mb();
+
+		/*
+		 * delay until the phases are settled when
+		 * the count is raised
+		 */
+		if (phase_count > pvreg->pmic_phase_count)
+			udelay(PHASE_SETTLING_TIME_US);
+
+		pvreg->pmic_phase_count = phase_count;
+	}
+
+	return rc;
+}
+
+static unsigned int _get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+	int coeff_total;
+	int rc;
+
+	kvreg->online_at_probe &= ~WAIT_FOR_LOAD;
+	coeff_total = get_coeff_total(kvreg);
+
+	rc = pmic_gang_set_phases(kvreg, coeff_total);
+	if (rc < 0) {
+		dev_err(&rdev->dev, "%s failed set mode %d rc = %d\n",
+				kvreg->name, coeff_total, rc);
+	}
+
+	return kvreg->mode;
+}
+
+static unsigned int krait_power_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+	int rc;
+
+	mutex_lock(&pvreg->krait_power_vregs_lock);
+	kvreg->load = load_uA;
+	if (!kvreg->online) {
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		return kvreg->mode;
+	}
+
+	rc = _get_optimum_mode(rdev, input_uV, output_uV, load_uA);
+	mutex_unlock(&pvreg->krait_power_vregs_lock);
+
+	return rc;
+}
+
+static int krait_power_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	return 0;
+}
+
+static unsigned int krait_power_get_mode(struct regulator_dev *rdev)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+
+	return kvreg->mode;
+}
+
 static int switch_to_using_hs(struct krait_power_vreg *kvreg)
 {
 	if (kvreg->mode == HS_MODE)
@@ -368,19 +600,6 @@
 	return 0;
 }
 
-static int set_pmic_gang_phases(struct pmic_gang_vreg *pvreg, int phase_count)
-{
-	pr_debug("programming phase_count = %d\n", phase_count);
-	if (pvreg->use_phase_switching)
-		/*
-		 * note the PMIC sets the phase count to one more than
-		 * the value in the register - hence subtract 1 from it
-		 */
-		return msm_spm_apcs_set_phase(phase_count - 1);
-	else
-		return 0;
-}
-
 static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
 {
 	int setpoint;
@@ -524,46 +743,6 @@
 	return rc;
 }
 
-#define PHASE_SETTLING_TIME_US		10
-static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
-				int load_uA)
-{
-	struct pmic_gang_vreg *pvreg = from->pvreg;
-	int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE);
-	int rc = 0;
-
-	if (phase_count <= 0)
-		phase_count = 1;
-
-	 /* Increase phases if it is less than the number of cpus online */
-	if (phase_count < num_online_cpus()) {
-		phase_count = num_online_cpus();
-	}
-
-	if (phase_count != pvreg->pmic_phase_count) {
-		rc = set_pmic_gang_phases(pvreg, phase_count);
-		if (rc < 0) {
-			dev_err(&from->rdev->dev,
-				"%s failed set phase %d rc = %d\n",
-				pvreg->name, phase_count, rc);
-			return rc;
-		}
-
-		/* complete the writes before the delay */
-		mb();
-
-		/*
-		 * delay until the phases are settled when
-		 * the count is raised
-		 */
-		if (phase_count > pvreg->pmic_phase_count)
-			udelay(PHASE_SETTLING_TIME_US);
-
-		pvreg->pmic_phase_count = phase_count;
-	}
-	return rc;
-}
-
 static int krait_power_get_voltage(struct regulator_dev *rdev)
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
@@ -590,21 +769,6 @@
 	return vmax;
 }
 
-static int get_total_load(struct krait_power_vreg *from)
-{
-	int load_total = 0;
-	struct krait_power_vreg *kvreg;
-	struct pmic_gang_vreg *pvreg = from->pvreg;
-
-	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
-			continue;
-		load_total += kvreg->load_uA;
-	}
-
-	return load_total;
-}
-
 #define ROUND_UP_VOLTAGE(v, res) (DIV_ROUND_UP(v, res) * res)
 static int _set_voltage(struct regulator_dev *rdev,
 			int orig_krait_uV, int requested_uV)
@@ -613,6 +777,7 @@
 	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
 	int rc;
 	int vmax;
+	int coeff_total;
 
 	pr_debug("%s: %d to %d\n", kvreg->name, orig_krait_uV, requested_uV);
 	/*
@@ -636,6 +801,11 @@
 				kvreg->name, requested_uV, orig_krait_uV, rc);
 	}
 
+	kvreg->online_at_probe &= ~WAIT_FOR_VOLTAGE;
+	coeff_total = get_coeff_total(kvreg);
+	/* adjust the phases since coeff2 would have changed */
+	rc = pmic_gang_set_phases(kvreg, coeff_total);
+
 	return rc;
 }
 
@@ -670,89 +840,6 @@
 	return rc;
 }
 
-#define PMIC_FTS_MODE_PFM	0x00
-#define PMIC_FTS_MODE_PWM	0x80
-#define PFM_LOAD_UA		500000
-static unsigned int _get_optimum_mode(struct regulator_dev *rdev,
-			int input_uV, int output_uV, int load_uA)
-{
-	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
-	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
-	int rc;
-	int load_total_uA;
-
-	load_total_uA = get_total_load(kvreg);
-
-	if (load_total_uA < PFM_LOAD_UA) {
-		if (!pvreg->pfm_mode) {
-			rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
-			if (rc) {
-				dev_err(&rdev->dev,
-					"%s enter PFM failed load %d rc = %d\n",
-					kvreg->name, load_total_uA, rc);
-				goto out;
-			} else {
-				pvreg->pfm_mode = true;
-			}
-		}
-		return kvreg->mode;
-	}
-
-	if (pvreg->pfm_mode) {
-		rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PWM);
-		if (rc) {
-			dev_err(&rdev->dev,
-				"%s exit PFM failed load %d rc = %d\n",
-				kvreg->name, load_total_uA, rc);
-			goto out;
-		} else {
-			pvreg->pfm_mode = false;
-		}
-	}
-
-	rc = pmic_gang_set_phases(kvreg, load_total_uA);
-	if (rc < 0) {
-		dev_err(&rdev->dev, "%s failed set mode %d rc = %d\n",
-				kvreg->name, load_total_uA, rc);
-		goto out;
-	}
-
-out:
-	return kvreg->mode;
-}
-
-static unsigned int krait_power_get_optimum_mode(struct regulator_dev *rdev,
-			int input_uV, int output_uV, int load_uA)
-{
-	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
-	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
-	int rc;
-
-	mutex_lock(&pvreg->krait_power_vregs_lock);
-	kvreg->load_uA = load_uA;
-	if (!kvreg->online) {
-		mutex_unlock(&pvreg->krait_power_vregs_lock);
-		return kvreg->mode;
-	}
-
-	rc = _get_optimum_mode(rdev, input_uV, output_uV, load_uA);
-	mutex_unlock(&pvreg->krait_power_vregs_lock);
-
-	return rc;
-}
-
-static int krait_power_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	return 0;
-}
-
-static unsigned int krait_power_get_mode(struct regulator_dev *rdev)
-{
-	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
-
-	return kvreg->mode;
-}
-
 static int krait_power_is_enabled(struct regulator_dev *rdev)
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
@@ -769,7 +856,7 @@
 	mutex_lock(&pvreg->krait_power_vregs_lock);
 	__krait_power_mdd_enable(kvreg, true);
 	kvreg->online = true;
-	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
+	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
 	if (rc < 0)
 		goto en_err;
 	/*
@@ -791,8 +878,7 @@
 	mutex_lock(&pvreg->krait_power_vregs_lock);
 	kvreg->online = false;
 
-	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV,
-							kvreg->load_uA);
+	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
 	if (rc < 0)
 		goto dis_err;
 
@@ -851,8 +937,10 @@
 DEFINE_SIMPLE_ATTRIBUTE(retention_fops,
 			get_retention_dbg_uV, set_retention_dbg_uV, "%llu\n");
 
+#define CPU_PWR_CTL_ONLINE_MASK 0x80
 static void kvreg_hw_init(struct krait_power_vreg *kvreg)
 {
+	int online;
 	/*
 	 * bhs_cnt value sets the ramp-up time from power collapse,
 	 * initialize the ramp up time
@@ -865,6 +953,10 @@
 	/* Enable MDD */
 	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
 	mb();
+	online = CPU_PWR_CTL_ONLINE_MASK
+			& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
+	kvreg->online_at_probe
+		= online ? (WAIT_FOR_LOAD | WAIT_FOR_VOLTAGE) : 0x0;
 }
 
 static void glb_init(void __iomem *apcs_gcc_base)
@@ -1012,7 +1104,7 @@
 	kvreg->desc.ops		= &krait_power_ops;
 	kvreg->desc.type	= REGULATOR_VOLTAGE;
 	kvreg->desc.owner	= THIS_MODULE;
-	kvreg->uV		= CORE_VOLTAGE_MIN;
+	kvreg->uV		= CORE_VOLTAGE_BOOTUP;
 	kvreg->mode		= HS_MODE;
 	kvreg->desc.ops		= &krait_power_ops;
 	kvreg->headroom_uV	= headroom_uV;
@@ -1111,6 +1203,7 @@
 {
 	int rc;
 	bool use_phase_switching = false;
+	int pfm_threshold;
 	struct device *dev = &pdev->dev;
 	struct device_node *node = dev->of_node;
 	struct pmic_gang_vreg *pvreg;
@@ -1123,6 +1216,13 @@
 
 	use_phase_switching = of_property_read_bool(node,
 						"qcom,use-phase-switching");
+
+	rc = of_property_read_u32(node, "qcom,pfm-threshold", &pfm_threshold);
+	if (rc < 0) {
+		dev_err(dev, "pfm-threshold missing rc=%d, pfm disabled\n", rc);
+		return -EINVAL;
+	}
+
 	pvreg = devm_kzalloc(&pdev->dev,
 			sizeof(struct pmic_gang_vreg), GFP_KERNEL);
 	if (!pvreg) {
@@ -1148,6 +1248,7 @@
 	pvreg->retention_enabled = true;
 	pvreg->pmic_min_uV_for_retention = INT_MAX;
 	pvreg->use_phase_switching = use_phase_switching;
+	pvreg->pfm_threshold = pfm_threshold;
 
 	mutex_init(&pvreg->krait_power_vregs_lock);
 	INIT_LIST_HEAD(&pvreg->krait_power_vregs);
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index d71787c..5f85ee9 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -152,8 +152,8 @@
 		if (mt->flags & MEMTYPE_FLAGS_1M_ALIGN)
 			mt->size = (mt->size + SECTION_SIZE - 1) & SECTION_MASK;
 		if (mt->size > mt->limit) {
-			pr_warning("%lx size for %s too large, setting to %lx\n",
-				mt->size, memtype_name[i], mt->limit);
+			pr_warning("%pa size for %s too large, setting to %pa\n",
+				&mt->size, memtype_name[i], &mt->limit);
 			mt->size = mt->limit;
 		}
 	}
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 09f784d..fcd7cef 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -70,9 +70,6 @@
 #define MSM_MPM_IRQ_INDEX(irq)  (irq / 32)
 #define MSM_MPM_IRQ_MASK(irq)  BIT(irq % 32)
 
-#define MSM_MPM_DETECT_CTL_INDEX(irq) (irq / 16)
-#define MSM_MPM_DETECT_CTL_SHIFT(irq) ((irq % 16) * 2)
-
 #define hashfn(val) (val % MSM_MPM_NR_MPM_IRQS)
 #define SCLK_HZ (32768)
 #define ARCH_TIMER_HZ (19200000)
@@ -81,8 +78,8 @@
 enum mpm_reg_offsets {
 	MSM_MPM_REG_WAKEUP,
 	MSM_MPM_REG_ENABLE,
-	MSM_MPM_REG_DETECT_CTL,
-	MSM_MPM_REG_DETECT_CTL1,
+	MSM_MPM_REG_FALLING_EDGE,
+	MSM_MPM_REG_RISING_EDGE,
 	MSM_MPM_REG_POLARITY,
 	MSM_MPM_REG_STATUS,
 };
@@ -91,7 +88,8 @@
 
 static uint32_t msm_mpm_enabled_irq[MSM_MPM_REG_WIDTH];
 static uint32_t msm_mpm_wake_irq[MSM_MPM_REG_WIDTH];
-static uint32_t msm_mpm_detect_ctl[MSM_MPM_REG_WIDTH * 2];
+static uint32_t msm_mpm_falling_edge[MSM_MPM_REG_WIDTH];
+static uint32_t msm_mpm_rising_edge[MSM_MPM_REG_WIDTH];
 static uint32_t msm_mpm_polarity[MSM_MPM_REG_WIDTH];
 
 enum {
@@ -174,11 +172,11 @@
 		reg = MSM_MPM_REG_ENABLE;
 		msm_mpm_write(reg, i, irqs[i]);
 
-		reg = MSM_MPM_REG_DETECT_CTL;
-		msm_mpm_write(reg, i, msm_mpm_detect_ctl[i]);
+		reg = MSM_MPM_REG_FALLING_EDGE;
+		msm_mpm_write(reg, i, msm_mpm_falling_edge[i]);
 
-		reg = MSM_MPM_REG_DETECT_CTL1;
-		msm_mpm_write(reg, i, msm_mpm_detect_ctl[2+i]);
+		reg = MSM_MPM_REG_RISING_EDGE;
+		msm_mpm_write(reg, i, msm_mpm_rising_edge[i]);
 
 		reg = MSM_MPM_REG_POLARITY;
 		msm_mpm_write(reg, i, msm_mpm_polarity[i]);
@@ -264,23 +262,24 @@
 	return 0;
 }
 
-static void msm_mpm_set_detect_ctl(int pin, unsigned int flow_type)
+static void msm_mpm_set_edge_ctl(int pin, unsigned int flow_type)
 {
 	uint32_t index;
-	uint32_t val = 0;
-	uint32_t shift;
+	uint32_t mask;
 
-	index = MSM_MPM_DETECT_CTL_INDEX(pin);
-	shift = MSM_MPM_DETECT_CTL_SHIFT(pin);
-
-	if (flow_type & IRQ_TYPE_EDGE_RISING)
-		val |= 0x02;
+	index = MSM_MPM_IRQ_INDEX(pin);
+	mask = MSM_MPM_IRQ_MASK(pin);
 
 	if (flow_type & IRQ_TYPE_EDGE_FALLING)
-		val |= 0x01;
+		msm_mpm_falling_edge[index] |= mask;
+	else
+		msm_mpm_falling_edge[index] &= ~mask;
 
-	msm_mpm_detect_ctl[index] &= ~(0x3 << shift);
-	msm_mpm_detect_ctl[index] |= (val & 0x03) << shift;
+	if (flow_type & IRQ_TYPE_EDGE_RISING)
+		msm_mpm_rising_edge[index] |= mask;
+	else
+		msm_mpm_rising_edge[index] &= ~mask;
+
 }
 
 static int msm_mpm_set_irq_type_exclusive(
@@ -300,7 +299,7 @@
 		if (index >= MSM_MPM_REG_WIDTH)
 			return -EFAULT;
 
-		msm_mpm_set_detect_ctl(mpm_irq, flow_type);
+		msm_mpm_set_edge_ctl(mpm_irq, flow_type);
 
 		if (flow_type &  IRQ_TYPE_LEVEL_HIGH)
 			msm_mpm_polarity[index] |= mask;
@@ -429,7 +428,7 @@
 
 	spin_lock_irqsave(&msm_mpm_lock, flags);
 
-	msm_mpm_set_detect_ctl(pin, flow_type);
+	msm_mpm_set_edge_ctl(pin, flow_type);
 
 	if (flow_type & IRQ_TYPE_LEVEL_HIGH)
 		msm_mpm_polarity[index] |= mask;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
index b9a553a..af3537c 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -79,9 +79,10 @@
 	}
 
 	pdata->num_usecases = num_usecases;
-	ret = of_property_read_u32(of_node, "qcom,msm-bus,active-only",
-		&pdata->active_only);
-	if (ret) {
+
+	if (of_property_read_bool(of_node, "qcom,msm-bus,active-only"))
+		pdata->active_only = 1;
+	else {
 		pr_debug("active_only flag absent.\n");
 		pr_debug("Using dual context by default\n");
 	}
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index db67f7d..0ada902 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -36,8 +36,8 @@
 #include <mach/msm_smsm.h>
 #include <mach/msm_dsps.h>
 #include <mach/subsystem_restart.h>
+#include <mach/ramdump.h>
 
-#include "ramdump.h"
 #include "timer.h"
 
 #define DRV_NAME	"msm_dsps"
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 4e8674c..056da7d 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -36,9 +36,9 @@
 #include <asm-generic/io-64-nonatomic-lo-hi.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
-#include "ramdump.h"
 
 #define pil_err(desc, fmt, ...)						\
 	dev_err(desc->dev, "%s: " fmt, desc->name, ##__VA_ARGS__)
@@ -335,6 +335,14 @@
 	unsigned int mask;
 	size_t size = max_addr - min_addr;
 
+	/* Don't reallocate due to fragmentation concerns, just sanity check */
+	if (priv->region) {
+		if (WARN(priv->region_end - priv->region_start < size,
+			"Can't reuse PIL memory, too small\n"))
+			return -ENOMEM;
+		return 0;
+	}
+
 	if (!ion) {
 		WARN_ON_ONCE("No ION client, can't support relocation\n");
 		return -ENOMEM;
@@ -471,9 +479,6 @@
 	writeq(0, &priv->info->start);
 	writel_relaxed(0, &priv->info->size);
 
-	if (priv->region)
-		ion_free(ion, priv->region);
-	priv->region = NULL;
 	list_for_each_entry_safe(p, tmp, &priv->segs, list) {
 		list_del(&p->list);
 		kfree(p);
@@ -661,8 +666,13 @@
 	release_firmware(fw);
 out:
 	up_read(&pil_pm_rwsem);
-	if (ret)
+	if (ret) {
+		if (priv->region) {
+			ion_free(ion, priv->region);
+			priv->region = NULL;
+		}
 		pil_release_mmap(desc);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(pil_boot);
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 65d60d6..df5ea35 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -21,10 +21,10 @@
 
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
-#include "ramdump.h"
 
 #define PPSS_RESET			0x2594
 #define PPSS_RESET_PROC_RESET		0x2
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index c9e2e0d..d44add6 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -29,11 +29,11 @@
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 #include <mach/subsystem_restart.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 #include "smd_private.h"
-#include "ramdump.h"
 
 #define GSS_CSR_AHB_CLK_SEL	0x0
 #define GSS_CSR_RESET		0x4
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index e95fae8..30f480a 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -24,11 +24,11 @@
 
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
+#include <mach/ramdump.h>
 
 #include "modem_notifier.h"
 #include "peripheral-loader.h"
 #include "scm-pas.h"
-#include "ramdump.h"
 
 #define MARM_BOOT_CONTROL		0x0010
 #define MARM_RESET			0x2BD4
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index edaa60c..0df8739 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -29,10 +29,10 @@
 
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
-#include "ramdump.h"
 
 #define PRONTO_PMU_COMMON_GDSCR				0x24
 #define PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE		BIT(0)
@@ -410,6 +410,15 @@
 	int ret, err_fatal_gpio, irq;
 	uint32_t regval;
 
+	int clk_ready = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-proxy-unvote", 0);
+	if (clk_ready < 0)
+		return clk_ready;
+
+	clk_ready = gpio_to_irq(clk_ready);
+	if (clk_ready < 0)
+		return clk_ready;
+
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
@@ -460,6 +469,7 @@
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = 10000;
+	desc->proxy_unvote_irq = clk_ready;
 
 	if (pas_supported(PAS_WCNSS) > 0) {
 		desc->ops = &pil_pronto_ops_trusted;
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 66adc2b..0575a3d 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -23,8 +23,8 @@
 
 #include <mach/subsystem_restart.h>
 #include <mach/scm.h>
+#include <mach/ramdump.h>
 
-#include "ramdump.h"
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index 1387433..f05bcdb 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.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
@@ -24,9 +24,9 @@
 #include <mach/scm.h>
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
+#include <mach/ramdump.h>
 
 #include "smd_private.h"
-#include "ramdump.h"
 #include "sysmon.h"
 #include "peripheral-loader.h"
 #include "pil-q6v4.h"
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index f2b090f..1821ab1 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.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
@@ -22,9 +22,9 @@
 
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
+#include <mach/ramdump.h>
 
 #include "smd_private.h"
-#include "ramdump.h"
 #include "peripheral-loader.h"
 #include "pil-q6v4.h"
 #include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 72253fd..3b2bbf3 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -27,11 +27,11 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/scm.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 #include "scm-pas.h"
-#include "ramdump.h"
 #include "sysmon.h"
 
 #define QDSP6SS_RST_EVB			0x010
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index cfd8daf..8f7d262 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -30,10 +30,10 @@
 #include <mach/subsystem_restart.h>
 #include <mach/clk.h>
 #include <mach/msm_smsm.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
-#include "ramdump.h"
 #include "sysmon.h"
 
 /* Q6 Register Offsets */
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 33301de..a2665b4 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,10 +23,10 @@
 #include <linux/wcnss_wlan.h>
 
 #include <mach/subsystem_restart.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
-#include "ramdump.h"
 #include "smd_private.h"
 
 #define RIVA_PMU_A2XB_CFG		0xB8
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index b0150d4..4e9e54b 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -30,10 +30,10 @@
 #include <mach/subsystem_restart.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
+#include <mach/ramdump.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
-#include "ramdump.h"
 
 /* VENUS WRAPPER registers */
 #define VENUS_WRAPPER_HW_VERSION			0x0
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 3c50bc6..cd1eaaf 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1229,18 +1229,11 @@
 	},
 };
 
-static int __devinit msm_pm_init(void)
+static int __init msm_pm_setup_saved_state(void)
 {
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
 	unsigned long pmdval;
-	enum msm_pm_time_stats_id enable_stats[] = {
-		MSM_PM_STAT_IDLE_WFI,
-		MSM_PM_STAT_RETENTION,
-		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
-		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-		MSM_PM_STAT_SUSPEND,
-	};
 	unsigned long exit_phys;
 
 	/* Page table for cores to come back up safely. */
@@ -1280,6 +1273,19 @@
 	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
 		     virt_to_phys(&msm_pm_pc_pgd));
 
+	return 0;
+}
+core_initcall(msm_pm_setup_saved_state);
+
+static int __init msm_pm_init(void)
+{
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_RETENTION,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+	};
 	msm_pm_mode_sysfs_add();
 	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
 	suspend_set_ops(&msm_pm_ops);
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index ccc2519..249032f 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -46,7 +46,7 @@
 		.idle_supported = 0,
 		.suspend_supported = 1,
 		.idle_enabled = 0,
-		.suspend_enabled = 0,
+		.suspend_enabled = 1,
 	},
 
 	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
@@ -74,7 +74,7 @@
 		.idle_supported = 0,
 		.suspend_supported = 1,
 		.idle_enabled = 0,
-		.suspend_enabled = 0,
+		.suspend_enabled = 1,
 	},
 
 	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
@@ -102,7 +102,7 @@
 		.idle_supported = 0,
 		.suspend_supported = 1,
 		.idle_enabled = 0,
-		.suspend_enabled = 0,
+		.suspend_enabled = 1,
 	},
 
 	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
diff --git a/arch/arm/mach-msm/ramdump.c b/arch/arm/mach-msm/ramdump.c
index 7f09a56..be21025 100644
--- a/arch/arm/mach-msm/ramdump.c
+++ b/arch/arm/mach-msm/ramdump.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -25,7 +25,7 @@
 #include <linux/elf.h>
 #include <linux/wait.h>
 
-#include "ramdump.h"
+#include <mach/ramdump.h>
 
 #define RAMDUMP_WAIT_MSECS	120000
 
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index 176c3de..cb8ed19 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -63,6 +63,8 @@
 	u32 count;
 	u64 last_entered_at;
 	u64 last_exited_at;
+	u64 accumulated;
+	u32 reserved[4];
 };
 
 static inline u64 get_time_in_sec(u64 counter)
@@ -84,6 +86,7 @@
 	char stat_type[5];
 	u64 time_in_last_mode;
 	u64 time_since_last_mode;
+	u64 actual_last_sleep;
 
 	stat_type[4] = 0;
 	memcpy(stat_type, &data->stat_type, sizeof(u32));
@@ -92,12 +95,13 @@
 	time_in_last_mode = get_time_in_msec(time_in_last_mode);
 	time_since_last_mode = arch_counter_get_cntpct() - data->last_exited_at;
 	time_since_last_mode = get_time_in_sec(time_since_last_mode);
+	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",
+		"time since last mode(sec):%llu\n actual last sleep(msec):%llu\n",
 		stat_type, data->count, time_in_last_mode,
-		time_since_last_mode);
+		time_since_last_mode, actual_last_sleep);
 }
 
 static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
@@ -140,6 +144,9 @@
 				i, offsetof(struct msm_rpm_stats_data_v2,
 					last_exited_at));
 
+		data.accumulated = msm_rpmstats_read_quad_register_v2(reg,
+				i, offsetof(struct msm_rpm_stats_data_v2,
+					accumulated));
 		length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
 				&data, sizeof(prvdata->buf) - length);
 		prvdata->read_idx++;
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index f1a7185..f48b538 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -262,7 +262,7 @@
 	rate = clk_round_rate(scm_clocks[CORE_CLK_SRC], 1);
 	clk_set_rate(scm_clocks[CORE_CLK_SRC], rate);
 
-	if (cpu_is_msm8974() || cpu_is_msm8226()) {
+	if (cpu_is_msm8974() || cpu_is_msm8226() || cpu_is_msm8610()) {
 		scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
 		scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
 	} else {
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 40ef20e..8a9042e 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -38,6 +38,7 @@
 #include <linux/suspend.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
@@ -45,11 +46,12 @@
 #include <mach/socinfo.h>
 #include <mach/proc_comm.h>
 #include <mach/msm_ipc_logging.h>
+#include <mach/ramdump.h>
+
 #include <asm/cacheflush.h>
 
 #include "smd_private.h"
 #include "modem_notifier.h"
-#include "ramdump.h"
 
 #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
 	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 169df1e..361df33 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -33,6 +33,8 @@
 #include <mach/msm_iomap.h>
 #include <mach/smem_log.h>
 
+#include <asm/arch_timer.h>
+
 #include "smd_private.h"
 #include "smd_rpc_sym.h"
 #include "modem_notifier.h"
@@ -652,13 +654,7 @@
 #else
 static inline unsigned int read_timestamp(void)
 {
-	unsigned long long val;
-
-	/* SMEM LOG uses a 32.768KHz timestamp */
-	val = sched_clock() * 32768U;
-	do_div(val, 1000000000U);
-
-	return (unsigned int)val;
+	return (unsigned int)(arch_counter_get_cntpct());
 }
 #endif
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 5158f8e..83f7a1d 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -351,6 +351,9 @@
 	/* zinc IDs */
 	[178] = MSM_CPU_ZINC,
 
+	/* krypton IDs */
+	[187] = MSM_CPU_KRYPTON,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
@@ -854,6 +857,10 @@
 		dummy_socinfo.id = 178;
 		strlcpy(dummy_socinfo.build_id, "msmzinc - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msmkrypton()) {
+		dummy_socinfo.id = 187;
+		strlcpy(dummy_socinfo.build_id, "msmkrypton - ",
+			sizeof(dummy_socinfo.build_id));
 	}
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
 		sizeof(dummy_socinfo.build_id));
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
index cccca26..95a85f26 100644
--- a/arch/arm/mach-msm/wdog_debug.c
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -24,7 +24,7 @@
 	ret = scm_call_atomic2(SCM_SVC_BOOT,
 			       SCM_WDOG_DEBUG_BOOT_PART, 0, BOOT_PART_EN_VAL);
 	if (ret)
-		pr_err("failed to enable wdog debug\n");
+		pr_err("failed to enable wdog debug: %d\n", ret);
 }
 EXPORT_SYMBOL(msm_enable_wdog_debug);
 
@@ -35,6 +35,6 @@
 	ret = scm_call_atomic2(SCM_SVC_BOOT,
 			       SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
 	if (ret)
-		pr_err("failed to disable wdog debug\n");
+		pr_err("failed to disable wdog debug: %d\n", ret);
 }
 EXPORT_SYMBOL(msm_disable_wdog_debug);
diff --git a/block/row-iosched.c b/block/row-iosched.c
index 3baec8c..c8ba344 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -158,6 +158,20 @@
 };
 
 /**
+ * struct starvation_data - data for starvation management
+ * @starvation_limit:	number of times this priority class
+ *			can tolerate being starved
+ * @starvation_counter:	number of requests from higher
+ *			priority classes that were dispatched while this
+ *			priority request were pending
+ *
+ */
+struct starvation_data {
+	int				starvation_limit;
+	int				starvation_counter;
+};
+
+/**
  * struct row_queue - Per block device rqueue structure
  * @dispatch_queue:	dispatch rqueue
  * @row_queues:		array of priority request queues
@@ -170,6 +184,8 @@
  *			complete.
  * @pending_urgent_rq:	pointer to the pending urgent request
  * @last_served_ioprio_class: I/O priority class that was last dispatched from
+ * @reg_prio_starvation: starvation data for REGULAR priority queues
+ * @low_prio_starvation: starvation data for LOW priority queues
  * @cycle_flags:	used for marking unserved queueus
  *
  */
@@ -183,6 +199,12 @@
 	bool				urgent_in_flight;
 	struct request			*pending_urgent_rq;
 	int				last_served_ioprio_class;
+
+#define	ROW_REG_STARVATION_TOLLERANCE	50
+	struct starvation_data		reg_prio_starvation;
+#define	ROW_LOW_STARVATION_TOLLERANCE	1000
+	struct starvation_data		low_prio_starvation;
+
 	unsigned int			cycle_flags;
 };
 
@@ -258,6 +280,42 @@
 	return HRTIMER_NORESTART;
 }
 
+/*
+ * row_regular_req_pending() - Check if there are REGULAR priority requests
+ *				 Pending in scheduler
+ * @rd:		pointer to struct row_data
+ *
+ * Returns True if there are REGULAR priority requests in scheduler queues.
+ *		False, otherwise.
+ */
+static inline bool row_regular_req_pending(struct row_data *rd)
+{
+	int i;
+
+	for (i = ROWQ_REG_PRIO_IDX; i < ROWQ_LOW_PRIO_IDX; i++)
+		if (!list_empty(&rd->row_queues[i].fifo))
+			return true;
+	return false;
+}
+
+/*
+ * row_low_req_pending() - Check if there are LOW priority requests
+ *				 Pending in scheduler
+ * @rd:		pointer to struct row_data
+ *
+ * Returns True if there are LOW priority requests in scheduler queues.
+ *		False, otherwise.
+ */
+static inline bool row_low_req_pending(struct row_data *rd)
+{
+	int i;
+
+	for (i = ROWQ_LOW_PRIO_IDX; i < ROWQ_MAX_PRIO; i++)
+		if (!list_empty(&rd->row_queues[i].fifo))
+			return true;
+	return false;
+}
+
 /******************* Elevator callback functions *********************/
 
 /*
@@ -272,6 +330,7 @@
 	struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
 	struct row_queue *rqueue = RQ_ROWQ(rq);
 	s64 diff_ms;
+	bool queue_was_empty = list_empty(&rqueue->fifo);
 
 	list_add_tail(&rq->queuelist, &rqueue->fifo);
 	rd->nr_reqs[rq_data_dir(rq)]++;
@@ -316,7 +375,8 @@
 	    !rd->pending_urgent_rq && !rd->urgent_in_flight) {
 		/* Handle High Priority queues */
 		if (rqueue->prio < ROWQ_REG_PRIO_IDX &&
-		    rd->last_served_ioprio_class != IOPRIO_CLASS_RT) {
+		    rd->last_served_ioprio_class != IOPRIO_CLASS_RT &&
+		    queue_was_empty) {
 			row_log_rowq(rd, rqueue->prio,
 				"added (high prio) urgent request");
 			rq->cmd_flags |= REQ_URGENT;
@@ -472,12 +532,21 @@
 	row_log_rowq(rd, rqueue->prio,
 		" Dispatched request %p nr_disp = %d", rq,
 		rqueue->nr_dispatched);
-	if (rqueue->prio < ROWQ_REG_PRIO_IDX)
+	if (rqueue->prio < ROWQ_REG_PRIO_IDX) {
 		rd->last_served_ioprio_class = IOPRIO_CLASS_RT;
-	else if (rqueue->prio < ROWQ_LOW_PRIO_IDX)
+		if (row_regular_req_pending(rd))
+			rd->reg_prio_starvation.starvation_counter++;
+		if (row_low_req_pending(rd))
+			rd->low_prio_starvation.starvation_counter++;
+	} else if (rqueue->prio < ROWQ_LOW_PRIO_IDX) {
 		rd->last_served_ioprio_class = IOPRIO_CLASS_BE;
-	else
+		rd->reg_prio_starvation.starvation_counter = 0;
+		if (row_low_req_pending(rd))
+			rd->low_prio_starvation.starvation_counter++;
+	} else {
 		rd->last_served_ioprio_class = IOPRIO_CLASS_IDLE;
+		rd->low_prio_starvation.starvation_counter = 0;
+	}
 }
 
 /*
@@ -517,7 +586,18 @@
 				rd->rd_idle_data.idling_queue_idx =
 					ROWQ_MAX_PRIO;
 			}
-			ret = IOPRIO_CLASS_RT;
+
+			if (row_regular_req_pending(rd) &&
+			    (rd->reg_prio_starvation.starvation_counter >=
+			     rd->reg_prio_starvation.starvation_limit))
+				ret = IOPRIO_CLASS_BE;
+			else if (row_low_req_pending(rd) &&
+			    (rd->low_prio_starvation.starvation_counter >=
+			     rd->low_prio_starvation.starvation_limit))
+				ret = IOPRIO_CLASS_IDLE;
+			else
+				ret = IOPRIO_CLASS_RT;
+
 			goto done;
 		}
 	}
@@ -546,7 +626,12 @@
 			    !force && row_queues_def[i].idling_enabled)
 				goto initiate_idling;
 		} else {
-			ret = IOPRIO_CLASS_BE;
+			if (row_low_req_pending(rd) &&
+			    (rd->low_prio_starvation.starvation_counter >=
+			     rd->low_prio_starvation.starvation_limit))
+				ret = IOPRIO_CLASS_IDLE;
+			else
+				ret = IOPRIO_CLASS_BE;
 			goto done;
 		}
 	}
@@ -716,6 +801,10 @@
 			ktime_set(0, 0);
 	}
 
+	rdata->reg_prio_starvation.starvation_limit =
+			ROW_REG_STARVATION_TOLLERANCE;
+	rdata->low_prio_starvation.starvation_limit =
+			ROW_LOW_STARVATION_TOLLERANCE;
 	/*
 	 * Currently idling is enabled only for READ queues. If we want to
 	 * enable it for write queues also, note that idling frequency will
@@ -865,42 +954,42 @@
 	return count;
 }
 
-#define SHOW_FUNCTION(__FUNC, __VAR, __CONV)				\
+#define SHOW_FUNCTION(__FUNC, __VAR)				\
 static ssize_t __FUNC(struct elevator_queue *e, char *page)		\
 {									\
 	struct row_data *rowd = e->elevator_data;			\
 	int __data = __VAR;						\
-	if (__CONV)							\
-		__data = jiffies_to_msecs(__data);			\
 	return row_var_show(__data, (page));			\
 }
 SHOW_FUNCTION(row_hp_read_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0);
+	rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum);
 SHOW_FUNCTION(row_rp_read_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0);
+	rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum);
 SHOW_FUNCTION(row_hp_swrite_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0);
+	rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum);
 SHOW_FUNCTION(row_rp_swrite_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0);
+	rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum);
 SHOW_FUNCTION(row_rp_write_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0);
+	rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum);
 SHOW_FUNCTION(row_lp_read_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0);
+	rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum);
 SHOW_FUNCTION(row_lp_swrite_quantum_show,
-	rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
-SHOW_FUNCTION(row_rd_idle_data_show, rowd->rd_idle_data.idle_time_ms, 0);
-SHOW_FUNCTION(row_rd_idle_data_freq_show, rowd->rd_idle_data.freq_ms, 0);
+	rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum);
+SHOW_FUNCTION(row_rd_idle_data_show, rowd->rd_idle_data.idle_time_ms);
+SHOW_FUNCTION(row_rd_idle_data_freq_show, rowd->rd_idle_data.freq_ms);
+SHOW_FUNCTION(row_reg_starv_limit_show,
+	rowd->reg_prio_starvation.starvation_limit);
+SHOW_FUNCTION(row_low_starv_limit_show,
+	rowd->low_prio_starvation.starvation_limit);
 #undef SHOW_FUNCTION
 
-#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)			\
+#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX)			\
 static ssize_t __FUNC(struct elevator_queue *e,				\
 		const char *page, size_t count)				\
 {									\
 	struct row_data *rowd = e->elevator_data;			\
 	int __data;						\
 	int ret = row_var_store(&__data, (page), count);		\
-	if (__CONV)							\
-		__data = (int)msecs_to_jiffies(__data);			\
 	if (__data < (MIN))						\
 		__data = (MIN);						\
 	else if (__data > (MAX))					\
@@ -909,29 +998,35 @@
 	return ret;							\
 }
 STORE_FUNCTION(row_hp_read_quantum_store,
-&rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 1, INT_MAX, 0);
+&rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 1, INT_MAX);
 STORE_FUNCTION(row_rp_read_quantum_store,
 			&rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_hp_swrite_quantum_store,
 			&rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_rp_swrite_quantum_store,
 			&rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_rp_write_quantum_store,
 			&rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_lp_read_quantum_store,
 			&rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_lp_swrite_quantum_store,
 			&rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_rd_idle_data_store, &rowd->rd_idle_data.idle_time_ms,
-			1, INT_MAX, 0);
+			1, INT_MAX);
 STORE_FUNCTION(row_rd_idle_data_freq_store, &rowd->rd_idle_data.freq_ms,
-			1, INT_MAX, 0);
+			1, INT_MAX);
+STORE_FUNCTION(row_reg_starv_limit_store,
+			&rowd->reg_prio_starvation.starvation_limit,
+			1, INT_MAX);
+STORE_FUNCTION(row_low_starv_limit_store,
+			&rowd->low_prio_starvation.starvation_limit,
+			1, INT_MAX);
 
 #undef STORE_FUNCTION
 
@@ -949,6 +1044,8 @@
 	ROW_ATTR(lp_swrite_quantum),
 	ROW_ATTR(rd_idle_data),
 	ROW_ATTR(rd_idle_data_freq),
+	ROW_ATTR(reg_starv_limit),
+	ROW_ATTR(low_starv_limit),
 	__ATTR_NULL
 };
 
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 2440404..8cc42df 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1530,6 +1530,45 @@
 
 }
 
+static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req,
+						struct qcedev_control *podev)
+{
+	/* if intending to use HW key make sure key fields are set
+	 * correctly and HW key is indeed supported in target
+	 */
+	if (req->encklen == 0) {
+		int i;
+		for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++)
+			if (req->enckey[i])
+				goto error;
+		if ((req->op != QCEDEV_OPER_ENC_NO_KEY) &&
+			(req->op != QCEDEV_OPER_DEC_NO_KEY))
+			if (!podev->platform_support.hw_key_support)
+				goto error;
+	} else {
+		if (req->encklen == QCEDEV_AES_KEY_192) {
+			if (!podev->ce_support.aes_key_192)
+				goto error;
+		} else {
+			/* if not using HW key make sure key
+			 * length is valid
+			 */
+			if ((req->mode == QCEDEV_AES_MODE_XTS)) {
+				if (!((req->encklen == QCEDEV_AES_KEY_128*2) ||
+					(req->encklen == QCEDEV_AES_KEY_256*2)))
+					goto error;
+			} else {
+				if (!((req->encklen == QCEDEV_AES_KEY_128) ||
+					(req->encklen == QCEDEV_AES_KEY_256)))
+					goto error;
+			}
+		}
+	}
+	return 0;
+error:
+	return -EINVAL;
+}
+
 static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
 						struct qcedev_control *podev)
 {
@@ -1542,36 +1581,13 @@
 	if ((req->alg >= QCEDEV_ALG_LAST) ||
 		(req->mode >= QCEDEV_AES_DES_MODE_LAST))
 		goto error;
-	if (req->alg == QCEDEV_ALG_AES) {
-		if ((req->mode == QCEDEV_AES_MODE_XTS) &&
-					(!podev->ce_support.aes_xts))
-			goto error;
-		/* if intending to use HW key make sure key fields are set
-		 * correctly and HW key is indeed supported in target
-		 */
-		if (req->encklen == 0) {
-			int i;
-			for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++)
-				if (req->enckey[i])
+
+	if ((req->mode == QCEDEV_AES_MODE_XTS) && (!podev->ce_support.aes_xts))
 					goto error;
-			if ((req->op != QCEDEV_OPER_ENC_NO_KEY) &&
-				(req->op != QCEDEV_OPER_DEC_NO_KEY))
-				if (!podev->platform_support.hw_key_support)
+
+	if (req->alg == QCEDEV_ALG_AES)
+		if (qcedev_check_cipher_key(req, podev))
 					goto error;
-		} else {
-			if (req->encklen == QCEDEV_AES_KEY_192) {
-				if (!podev->ce_support.aes_key_192)
-					goto error;
-			} else {
-				/* if not using HW key make sure key
-				 * length is valid
-				 */
-				if (!((req->encklen == QCEDEV_AES_KEY_128) ||
-					(req->encklen == QCEDEV_AES_KEY_256)))
-					goto error;
-			}
-		}
-	}
 	/* if using a byteoffset, make sure it is CTR mode using vbuf */
 	if (req->byteoffset) {
 		if (req->mode != QCEDEV_AES_MODE_CTR)
@@ -1607,6 +1623,11 @@
 	if (req->alg >= QCEDEV_ALG_SHA_ALG_LAST)
 		goto sha_error;
 
+	if ((req->alg == QCEDEV_ALG_SHA1_HMAC) ||
+			(req->alg == QCEDEV_ALG_SHA1_HMAC)) {
+		if (req->authklen == 0)
+			goto sha_error;
+	}
 	return 0;
 sha_error:
 	return -EINVAL;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 05ef87c..85c25c7 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -677,12 +677,10 @@
 	return 0;
 };
 
-static int _qcrypto_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key,
-		unsigned int len)
+
+static int _qcrypto_check_aes_keylen(struct crypto_ablkcipher *cipher,
+		struct crypto_priv *cp, unsigned int len)
 {
-	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
-	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-	struct crypto_priv *cp = ctx->cp;
 
 	switch (len) {
 	case AES_KEYSIZE_128:
@@ -695,8 +693,40 @@
 		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	};
-	ctx->enc_key_len = len;
-	memcpy(ctx->enc_key, key, len);
+
+	return 0;
+}
+
+static int _qcrypto_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key,
+		unsigned int len)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_priv *cp = ctx->cp;
+
+	if (_qcrypto_check_aes_keylen(cipher, cp, len)) {
+		return -EINVAL;
+	} else {
+		ctx->enc_key_len = len;
+		memcpy(ctx->enc_key, key, len);
+	}
+	return 0;
+};
+
+static int _qcrypto_setkey_aes_xts(struct crypto_ablkcipher *cipher,
+		const u8 *key, unsigned int len)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_priv *cp = ctx->cp;
+
+
+	if (_qcrypto_check_aes_keylen(cipher, cp, len/2)) {
+		return -EINVAL;
+	} else {
+		ctx->enc_key_len = len;
+		memcpy(ctx->enc_key, key, len);
+	}
 	return 0;
 };
 
@@ -3124,7 +3154,7 @@
 			.ivsize		= AES_BLOCK_SIZE,
 			.min_keysize	= AES_MIN_KEY_SIZE,
 			.max_keysize	= AES_MAX_KEY_SIZE,
-			.setkey		= _qcrypto_setkey_aes,
+			.setkey		= _qcrypto_setkey_aes_xts,
 			.encrypt	= _qcrypto_enc_aes_xts,
 			.decrypt	= _qcrypto_dec_aes_xts,
 		},
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 60a6b81..f4f9a92 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o
+obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o
 obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
 obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index d3434d8..a01ef3f 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -112,8 +112,6 @@
                 !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
 }
 
-static void ion_iommu_release(struct kref *kref);
-
 /* this function should only be called while dev->lock is held */
 static void ion_buffer_add(struct ion_device *dev,
 			   struct ion_buffer *buffer)
@@ -140,61 +138,6 @@
 	rb_insert_color(&buffer->node, &dev->buffers);
 }
 
-static void ion_iommu_add(struct ion_buffer *buffer,
-			  struct ion_iommu_map *iommu)
-{
-	struct rb_node **p = &buffer->iommu_maps.rb_node;
-	struct rb_node *parent = NULL;
-	struct ion_iommu_map *entry;
-
-	while (*p) {
-		parent = *p;
-		entry = rb_entry(parent, struct ion_iommu_map, node);
-
-		if (iommu->key < entry->key) {
-			p = &(*p)->rb_left;
-		} else if (iommu->key > entry->key) {
-			p = &(*p)->rb_right;
-		} else {
-			pr_err("%s: buffer %p already has mapping for domain %d"
-				" and partition %d\n", __func__,
-				buffer,
-				iommu_map_domain(iommu),
-				iommu_map_partition(iommu));
-			BUG();
-		}
-	}
-
-	rb_link_node(&iommu->node, parent, p);
-	rb_insert_color(&iommu->node, &buffer->iommu_maps);
-
-}
-
-static struct ion_iommu_map *ion_iommu_lookup(struct ion_buffer *buffer,
-						unsigned int domain_no,
-						unsigned int partition_no)
-{
-	struct rb_node **p = &buffer->iommu_maps.rb_node;
-	struct rb_node *parent = NULL;
-	struct ion_iommu_map *entry;
-	uint64_t key = domain_no;
-	key = key << 32 | partition_no;
-
-	while (*p) {
-		parent = *p;
-		entry = rb_entry(parent, struct ion_iommu_map, node);
-
-		if (key < entry->key)
-			p = &(*p)->rb_left;
-		else if (key > entry->key)
-			p = &(*p)->rb_right;
-		else
-			return entry;
-	}
-
-	return NULL;
-}
-
 static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
 
 /* this function should only be called while dev->lock is held */
@@ -275,38 +218,6 @@
 	return ERR_PTR(ret);
 }
 
-/**
- * Check for delayed IOMMU unmapping. Also unmap any outstanding
- * mappings which would otherwise have been leaked.
- */
-static void ion_iommu_delayed_unmap(struct ion_buffer *buffer)
-{
-	struct ion_iommu_map *iommu_map;
-	struct rb_node *node;
-	const struct rb_root *rb = &(buffer->iommu_maps);
-	unsigned long ref_count;
-	unsigned int delayed_unmap;
-
-	mutex_lock(&buffer->lock);
-
-	while ((node = rb_first(rb)) != 0) {
-		iommu_map = rb_entry(node, struct ion_iommu_map, node);
-		ref_count = atomic_read(&iommu_map->ref.refcount);
-		delayed_unmap = iommu_map->flags & ION_IOMMU_UNMAP_DELAYED;
-
-		if ((delayed_unmap && ref_count > 1) || !delayed_unmap) {
-			pr_err("%s: Virtual memory address leak in domain %u, partition %u\n",
-				__func__, iommu_map->domain_info[DI_DOMAIN_NUM],
-				iommu_map->domain_info[DI_PARTITION_NUM]);
-		}
-		/* set ref count to 1 to force release */
-		kref_init(&iommu_map->ref);
-		kref_put(&iommu_map->ref, ion_iommu_release);
-	}
-
-	mutex_unlock(&buffer->lock);
-}
-
 static void ion_delayed_unsecure(struct ion_buffer *buffer)
 {
 	if (buffer->heap->ops->unsecure_buffer)
@@ -323,7 +234,6 @@
 	buffer->heap->ops->unmap_dma(buffer->heap, buffer);
 
 	ion_delayed_unsecure(buffer);
-	ion_iommu_delayed_unmap(buffer);
 	buffer->heap->ops->free(buffer);
 	mutex_lock(&dev->lock);
 	rb_erase(&buffer->node, &dev->buffers);
@@ -654,212 +564,6 @@
 		ion_buffer_kmap_put(buffer);
 }
 
-static struct ion_iommu_map *__ion_iommu_map(struct ion_buffer *buffer,
-		int domain_num, int partition_num, unsigned long align,
-		unsigned long iova_length, unsigned long flags,
-		unsigned long *iova)
-{
-	struct ion_iommu_map *data;
-	int ret;
-
-	data = kmalloc(sizeof(*data), GFP_ATOMIC);
-
-	if (!data)
-		return ERR_PTR(-ENOMEM);
-
-	data->buffer = buffer;
-	iommu_map_domain(data) = domain_num;
-	iommu_map_partition(data) = partition_num;
-
-	ret = buffer->heap->ops->map_iommu(buffer, data,
-						domain_num,
-						partition_num,
-						align,
-						iova_length,
-						flags);
-
-	if (ret)
-		goto out;
-
-	kref_init(&data->ref);
-	*iova = data->iova_addr;
-
-	ion_iommu_add(buffer, data);
-
-	return data;
-
-out:
-	kfree(data);
-	return ERR_PTR(ret);
-}
-
-int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
-			int domain_num, int partition_num, unsigned long align,
-			unsigned long iova_length, unsigned long *iova,
-			unsigned long *buffer_size,
-			unsigned long flags, unsigned long iommu_flags)
-{
-	struct ion_buffer *buffer;
-	struct ion_iommu_map *iommu_map;
-	int ret = 0;
-
-	if (IS_ERR_OR_NULL(client)) {
-		pr_err("%s: client pointer is invalid\n", __func__);
-		return -EINVAL;
-	}
-	if (IS_ERR_OR_NULL(handle)) {
-		pr_err("%s: handle pointer is invalid\n", __func__);
-		return -EINVAL;
-	}
-	if (IS_ERR_OR_NULL(handle->buffer)) {
-		pr_err("%s: buffer pointer is invalid\n", __func__);
-		return -EINVAL;
-	}
-
-	if (ION_IS_CACHED(flags)) {
-		pr_err("%s: Cannot map iommu as cached.\n", __func__);
-		return -EINVAL;
-	}
-
-	mutex_lock(&client->lock);
-	if (!ion_handle_validate(client, handle)) {
-		pr_err("%s: invalid handle passed to map_kernel.\n",
-		       __func__);
-		mutex_unlock(&client->lock);
-		return -EINVAL;
-	}
-
-	buffer = handle->buffer;
-	mutex_lock(&buffer->lock);
-
-	if (!handle->buffer->heap->ops->map_iommu) {
-		pr_err("%s: map_iommu is not implemented by this heap.\n",
-		       __func__);
-		ret = -ENODEV;
-		goto out;
-	}
-
-	/*
-	 * If clients don't want a custom iova length, just use whatever
-	 * the buffer size is
-	 */
-	if (!iova_length)
-		iova_length = buffer->size;
-
-	if (buffer->size > iova_length) {
-		pr_debug("%s: iova length %lx is not at least buffer size"
-			" %x\n", __func__, iova_length, buffer->size);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (buffer->size & ~PAGE_MASK) {
-		pr_debug("%s: buffer size %x is not aligned to %lx", __func__,
-			buffer->size, PAGE_SIZE);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (iova_length & ~PAGE_MASK) {
-		pr_debug("%s: iova_length %lx is not aligned to %lx", __func__,
-			iova_length, PAGE_SIZE);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	iommu_map = ion_iommu_lookup(buffer, domain_num, partition_num);
-	if (!iommu_map) {
-		iommu_map = __ion_iommu_map(buffer, domain_num, partition_num,
-					    align, iova_length, flags, iova);
-		if (!IS_ERR_OR_NULL(iommu_map)) {
-			iommu_map->flags = iommu_flags;
-
-			if (iommu_map->flags & ION_IOMMU_UNMAP_DELAYED)
-				kref_get(&iommu_map->ref);
-		} else {
-			ret = PTR_ERR(iommu_map);
-		}
-	} else {
-		if (iommu_map->flags != iommu_flags) {
-			pr_err("%s: handle %p is already mapped with iommu flags %lx, trying to map with flags %lx\n",
-				__func__, handle,
-				iommu_map->flags, iommu_flags);
-			ret = -EINVAL;
-		} else if (iommu_map->mapped_size != iova_length) {
-			pr_err("%s: handle %p is already mapped with length"
-					" %x, trying to map with length %lx\n",
-				__func__, handle, iommu_map->mapped_size,
-				iova_length);
-			ret = -EINVAL;
-		} else {
-			kref_get(&iommu_map->ref);
-			*iova = iommu_map->iova_addr;
-		}
-	}
-	if (!ret)
-		buffer->iommu_map_cnt++;
-	*buffer_size = buffer->size;
-out:
-	mutex_unlock(&buffer->lock);
-	mutex_unlock(&client->lock);
-	return ret;
-}
-EXPORT_SYMBOL(ion_map_iommu);
-
-static void ion_iommu_release(struct kref *kref)
-{
-	struct ion_iommu_map *map = container_of(kref, struct ion_iommu_map,
-						ref);
-	struct ion_buffer *buffer = map->buffer;
-
-	rb_erase(&map->node, &buffer->iommu_maps);
-	buffer->heap->ops->unmap_iommu(map);
-	kfree(map);
-}
-
-void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle,
-			int domain_num, int partition_num)
-{
-	struct ion_iommu_map *iommu_map;
-	struct ion_buffer *buffer;
-
-	if (IS_ERR_OR_NULL(client)) {
-		pr_err("%s: client pointer is invalid\n", __func__);
-		return;
-	}
-	if (IS_ERR_OR_NULL(handle)) {
-		pr_err("%s: handle pointer is invalid\n", __func__);
-		return;
-	}
-	if (IS_ERR_OR_NULL(handle->buffer)) {
-		pr_err("%s: buffer pointer is invalid\n", __func__);
-		return;
-	}
-
-	mutex_lock(&client->lock);
-	buffer = handle->buffer;
-
-	mutex_lock(&buffer->lock);
-
-	iommu_map = ion_iommu_lookup(buffer, domain_num, partition_num);
-
-	if (!iommu_map) {
-		WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
-				domain_num, partition_num, buffer);
-		goto out;
-	}
-
-	kref_put(&iommu_map->ref, ion_iommu_release);
-
-	buffer->iommu_map_cnt--;
-out:
-	mutex_unlock(&buffer->lock);
-
-	mutex_unlock(&client->lock);
-
-}
-EXPORT_SYMBOL(ion_unmap_iommu);
-
 void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle)
 {
 	struct ion_buffer *buffer;
@@ -903,52 +607,10 @@
 }
 EXPORT_SYMBOL(ion_unmap_kernel);
 
-int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
-			void *uaddr, unsigned long offset, unsigned long len,
-			unsigned int cmd)
-{
-	struct ion_buffer *buffer;
-	int ret = -EINVAL;
-
-	mutex_lock(&client->lock);
-	if (!ion_handle_validate(client, handle)) {
-		pr_err("%s: invalid handle passed to do_cache_op.\n",
-		       __func__);
-		mutex_unlock(&client->lock);
-		return -EINVAL;
-	}
-	buffer = handle->buffer;
-	mutex_lock(&buffer->lock);
-
-	if (!ION_IS_CACHED(buffer->flags)) {
-		ret = 0;
-		goto out;
-	}
-
-	if (!handle->buffer->heap->ops->cache_op) {
-		pr_err("%s: cache_op is not implemented by this heap.\n",
-		       __func__);
-		ret = -ENODEV;
-		goto out;
-	}
-
-
-	ret = buffer->heap->ops->cache_op(buffer->heap, buffer, uaddr,
-						offset, len, cmd);
-
-out:
-	mutex_unlock(&buffer->lock);
-	mutex_unlock(&client->lock);
-	return ret;
-
-}
-EXPORT_SYMBOL(ion_do_cache_op);
-
 static int ion_debug_client_show(struct seq_file *s, void *unused)
 {
 	struct ion_client *client = s->private;
 	struct rb_node *n;
-	struct rb_node *n2;
 
 	seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
 			"heap_name", "size_in_bytes", "handle refcount",
@@ -973,15 +635,6 @@
 		else
 			seq_printf(s, " : %12s", "N/A");
 
-		for (n2 = rb_first(&handle->buffer->iommu_maps); n2;
-				   n2 = rb_next(n2)) {
-			struct ion_iommu_map *imap =
-				rb_entry(n2, struct ion_iommu_map, node);
-			seq_printf(s, " : [%d,%d] - %8lx",
-					imap->domain_info[DI_DOMAIN_NUM],
-					imap->domain_info[DI_PARTITION_NUM],
-					imap->iova_addr);
-		}
 		seq_printf(s, "\n");
 	}
 	mutex_unlock(&client->lock);
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 9610dfe..0dd3054 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -24,11 +24,9 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/iommu.h>
 #include <linux/seq_file.h>
 #include "ion_priv.h"
 
-#include <mach/iommu_domains.h>
 #include <asm/mach/map.h>
 #include <asm/cacheflush.h>
 #include <linux/msm_ion.h>
@@ -39,10 +37,6 @@
 	ion_phys_addr_t base;
 	unsigned long allocated_bytes;
 	unsigned long total_size;
-	int (*request_region)(void *);
-	int (*release_region)(void *);
-	atomic_t map_count;
-	void *bus_id;
 	unsigned int has_outer_cache;
 };
 
@@ -130,79 +124,33 @@
 	buffer->sg_table = 0;
 }
 
-static int ion_carveout_request_region(struct ion_carveout_heap *carveout_heap)
-{
-	int ret_value = 0;
-	if (atomic_inc_return(&carveout_heap->map_count) == 1) {
-		if (carveout_heap->request_region) {
-			ret_value = carveout_heap->request_region(
-						carveout_heap->bus_id);
-			if (ret_value) {
-				pr_err("Unable to request SMI region");
-				atomic_dec(&carveout_heap->map_count);
-			}
-		}
-	}
-	return ret_value;
-}
-
-static int ion_carveout_release_region(struct ion_carveout_heap *carveout_heap)
-{
-	int ret_value = 0;
-	if (atomic_dec_and_test(&carveout_heap->map_count)) {
-		if (carveout_heap->release_region) {
-			ret_value = carveout_heap->release_region(
-						carveout_heap->bus_id);
-			if (ret_value)
-				pr_err("Unable to release SMI region");
-		}
-	}
-	return ret_value;
-}
-
 void *ion_carveout_heap_map_kernel(struct ion_heap *heap,
 				   struct ion_buffer *buffer)
 {
-	struct ion_carveout_heap *carveout_heap =
-		container_of(heap, struct ion_carveout_heap, heap);
 	void *ret_value;
 
-	if (ion_carveout_request_region(carveout_heap))
-		return NULL;
-
 	if (ION_IS_CACHED(buffer->flags))
 		ret_value = ioremap_cached(buffer->priv_phys, buffer->size);
 	else
 		ret_value = ioremap(buffer->priv_phys, buffer->size);
 
-	if (!ret_value)
-		ion_carveout_release_region(carveout_heap);
 	return ret_value;
 }
 
 void ion_carveout_heap_unmap_kernel(struct ion_heap *heap,
 				    struct ion_buffer *buffer)
 {
-	struct ion_carveout_heap *carveout_heap =
-		container_of(heap, struct ion_carveout_heap, heap);
-
 	__arm_iounmap(buffer->vaddr);
 	buffer->vaddr = NULL;
 
-	ion_carveout_release_region(carveout_heap);
 	return;
 }
 
 int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 			       struct vm_area_struct *vma)
 {
-	struct ion_carveout_heap *carveout_heap =
-		container_of(heap, struct ion_carveout_heap, heap);
 	int ret_value = 0;
 
-	if (ion_carveout_request_region(carveout_heap))
-		return -EINVAL;
-
 	if (!ION_IS_CACHED(buffer->flags))
 		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
@@ -211,104 +159,9 @@
 			vma->vm_end - vma->vm_start,
 			vma->vm_page_prot);
 
-	if (ret_value)
-		ion_carveout_release_region(carveout_heap);
 	return ret_value;
 }
 
-void ion_carveout_heap_unmap_user(struct ion_heap *heap,
-				    struct ion_buffer *buffer)
-{
-	struct ion_carveout_heap *carveout_heap =
-		container_of(heap, struct ion_carveout_heap, heap);
-	ion_carveout_release_region(carveout_heap);
-}
-
-int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
-			void *vaddr, unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	void (*outer_cache_op)(phys_addr_t, phys_addr_t) = NULL;
-	struct ion_carveout_heap *carveout_heap =
-	     container_of(heap, struct  ion_carveout_heap, heap);
-	unsigned int size_to_vmap, total_size;
-	int i, j;
-	void *ptr = NULL;
-	ion_phys_addr_t buff_phys = buffer->priv_phys;
-
-	if (!vaddr) {
-		/*
-		 * Split the vmalloc space into smaller regions in
-		 * order to clean and/or invalidate the cache.
-		 */
-		size_to_vmap = ((VMALLOC_END - VMALLOC_START)/8);
-		total_size = buffer->size;
-
-		for (i = 0; i < total_size; i += size_to_vmap) {
-			size_to_vmap = min(size_to_vmap, total_size - i);
-			for (j = 0; j < 10 && size_to_vmap; ++j) {
-				ptr = ioremap(buff_phys, size_to_vmap);
-				if (ptr) {
-					switch (cmd) {
-					case ION_IOC_CLEAN_CACHES:
-						dmac_clean_range(ptr,
-							ptr + size_to_vmap);
-						outer_cache_op =
-							outer_clean_range;
-						break;
-					case ION_IOC_INV_CACHES:
-						dmac_inv_range(ptr,
-							ptr + size_to_vmap);
-						outer_cache_op =
-							outer_inv_range;
-						break;
-					case ION_IOC_CLEAN_INV_CACHES:
-						dmac_flush_range(ptr,
-							ptr + size_to_vmap);
-						outer_cache_op =
-							outer_flush_range;
-						break;
-					default:
-						return -EINVAL;
-					}
-					buff_phys += size_to_vmap;
-					break;
-				} else {
-					size_to_vmap >>= 1;
-				}
-			}
-			if (!ptr) {
-				pr_err("Couldn't io-remap the memory\n");
-				return -EINVAL;
-			}
-			iounmap(ptr);
-		}
-	} else {
-		switch (cmd) {
-		case ION_IOC_CLEAN_CACHES:
-			dmac_clean_range(vaddr, vaddr + length);
-			outer_cache_op = outer_clean_range;
-			break;
-		case ION_IOC_INV_CACHES:
-			dmac_inv_range(vaddr, vaddr + length);
-			outer_cache_op = outer_inv_range;
-			break;
-		case ION_IOC_CLEAN_INV_CACHES:
-			dmac_flush_range(vaddr, vaddr + length);
-			outer_cache_op = outer_flush_range;
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	if (carveout_heap->has_outer_cache) {
-		unsigned long pstart = buffer->priv_phys + offset;
-		outer_cache_op(pstart, pstart + length);
-	}
-	return 0;
-}
-
 static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
 				    const struct rb_root *mem_map)
 {
@@ -363,124 +216,16 @@
 	return 0;
 }
 
-int ion_carveout_heap_map_iommu(struct ion_buffer *buffer,
-					struct ion_iommu_map *data,
-					unsigned int domain_num,
-					unsigned int partition_num,
-					unsigned long align,
-					unsigned long iova_length,
-					unsigned long flags)
-{
-	struct iommu_domain *domain;
-	int ret = 0;
-	unsigned long extra;
-	struct scatterlist *sglist = 0;
-	int prot = IOMMU_WRITE | IOMMU_READ;
-	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
-
-	data->mapped_size = iova_length;
-
-	if (!msm_use_iommu()) {
-		data->iova_addr = buffer->priv_phys;
-		return 0;
-	}
-
-	extra = iova_length - buffer->size;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -ENOMEM;
-		goto out1;
-	}
-
-	sglist = vmalloc(sizeof(*sglist));
-	if (!sglist)
-		goto out1;
-
-	sg_init_table(sglist, 1);
-	sglist->length = buffer->size;
-	sglist->offset = 0;
-	sglist->dma_address = buffer->priv_phys;
-
-	ret = iommu_map_range(domain, data->iova_addr, sglist,
-			      buffer->size, prot);
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	if (extra) {
-		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		unsigned long phys_addr = sg_phys(sglist);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	vfree(sglist);
-	return ret;
-
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-out1:
-	vfree(sglist);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-out:
-
-	return ret;
-}
-
-void ion_carveout_heap_unmap_iommu(struct ion_iommu_map *data)
-{
-	unsigned int domain_num;
-	unsigned int partition_num;
-	struct iommu_domain *domain;
-
-	if (!msm_use_iommu())
-		return;
-
-	domain_num = iommu_map_domain(data);
-	partition_num = iommu_map_partition(data);
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
-		return;
-	}
-
-	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-	return;
-}
-
 static struct ion_heap_ops carveout_heap_ops = {
 	.allocate = ion_carveout_heap_allocate,
 	.free = ion_carveout_heap_free,
 	.phys = ion_carveout_heap_phys,
 	.map_user = ion_carveout_heap_map_user,
 	.map_kernel = ion_carveout_heap_map_kernel,
-	.unmap_user = ion_carveout_heap_unmap_user,
 	.unmap_kernel = ion_carveout_heap_unmap_kernel,
 	.map_dma = ion_carveout_heap_map_dma,
 	.unmap_dma = ion_carveout_heap_unmap_dma,
-	.cache_op = ion_carveout_cache_ops,
 	.print_debug = ion_carveout_print_debug,
-	.map_iommu = ion_carveout_heap_map_iommu,
-	.unmap_iommu = ion_carveout_heap_unmap_iommu,
 };
 
 struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
@@ -511,19 +256,6 @@
 	carveout_heap->total_size = heap_data->size;
 	carveout_heap->has_outer_cache = heap_data->has_outer_cache;
 
-	if (heap_data->extra_data) {
-		struct ion_co_heap_pdata *extra_data =
-				heap_data->extra_data;
-
-		if (extra_data->setup_region)
-			carveout_heap->bus_id = extra_data->setup_region();
-		if (extra_data->request_region)
-			carveout_heap->request_region =
-					extra_data->request_region;
-		if (extra_data->release_region)
-			carveout_heap->release_region =
-					extra_data->release_region;
-	}
 	return &carveout_heap->heap;
 }
 
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index 4f12e38..f64ad4d 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -178,148 +178,6 @@
 	return;
 }
 
-int ion_cma_map_iommu(struct ion_buffer *buffer,
-				struct ion_iommu_map *data,
-				unsigned int domain_num,
-				unsigned int partition_num,
-				unsigned long align,
-				unsigned long iova_length,
-				unsigned long flags)
-{
-	int ret = 0;
-	struct iommu_domain *domain;
-	unsigned long extra;
-	unsigned long extra_iova_addr;
-	struct ion_cma_buffer_info *info = buffer->priv_virt;
-	struct sg_table *table = info->table;
-	int prot = IOMMU_WRITE | IOMMU_READ;
-
-	data->mapped_size = iova_length;
-
-	if (!msm_use_iommu()) {
-		data->iova_addr = info->handle;
-		return 0;
-	}
-
-	extra = iova_length - buffer->size;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -EINVAL;
-		goto out1;
-	}
-
-	ret = iommu_map_range(domain, data->iova_addr, table->sgl,
-				buffer->size, prot);
-
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	extra_iova_addr = data->iova_addr + buffer->size;
-	if (extra) {
-		unsigned long phys_addr = sg_phys(table->sgl);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	return ret;
-
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-out1:
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-out:
-	return ret;
-}
-
-
-void ion_cma_unmap_iommu(struct ion_iommu_map *data)
-{
-	unsigned int domain_num;
-	unsigned int partition_num;
-	struct iommu_domain *domain;
-
-	if (!msm_use_iommu())
-		return;
-
-	domain_num = iommu_map_domain(data);
-	partition_num = iommu_map_partition(data);
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
-		return;
-	}
-
-	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-	return;
-}
-
-int ion_cma_cache_ops(struct ion_heap *heap,
-			struct ion_buffer *buffer, void *vaddr,
-			unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
-
-	switch (cmd) {
-	case ION_IOC_CLEAN_CACHES:
-		if (!vaddr)
-			dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_TO_DEVICE);
-		else
-			dmac_clean_range(vaddr, vaddr + length);
-		outer_cache_op = outer_clean_range;
-		break;
-	case ION_IOC_INV_CACHES:
-		if (!vaddr)
-			dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_FROM_DEVICE);
-		else
-			dmac_inv_range(vaddr, vaddr + length);
-		outer_cache_op = outer_inv_range;
-		break;
-	case ION_IOC_CLEAN_INV_CACHES:
-		if (!vaddr) {
-			dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_TO_DEVICE);
-			dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_FROM_DEVICE);
-		} else {
-			dmac_flush_range(vaddr, vaddr + length);
-		}
-		outer_cache_op = outer_flush_range;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (cma_heap_has_outer_cache) {
-		struct ion_cma_buffer_info *info = buffer->priv_virt;
-
-		outer_cache_op(info->handle, info->handle + length);
-	}
-
-	return 0;
-}
-
 static int ion_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
 			const struct rb_root *mem_map)
 {
@@ -358,9 +216,6 @@
 	.map_user = ion_cma_mmap,
 	.map_kernel = ion_cma_map_kernel,
 	.unmap_kernel = ion_cma_unmap_kernel,
-	.map_iommu = ion_cma_map_iommu,
-	.unmap_iommu = ion_cma_unmap_iommu,
-	.cache_op = ion_cma_cache_ops,
 	.print_debug = ion_cma_print_debug,
 };
 
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 0fbcfbf..d622a51 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -44,7 +44,6 @@
 	bool is_cached;
 };
 
-static int cma_heap_has_outer_cache;
 /*
  * Create scatter-list for the already allocated DMA buffer.
  * This function could be replace by dma_common_get_sgtable
@@ -212,110 +211,6 @@
 	return;
 }
 
-int ion_secure_cma_map_iommu(struct ion_buffer *buffer,
-				struct ion_iommu_map *data,
-				unsigned int domain_num,
-				unsigned int partition_num,
-				unsigned long align,
-				unsigned long iova_length,
-				unsigned long flags)
-{
-	int ret = 0;
-	struct iommu_domain *domain;
-	unsigned long extra;
-	unsigned long extra_iova_addr;
-	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
-	struct sg_table *table = info->table;
-	int prot = IOMMU_WRITE | IOMMU_READ;
-
-	data->mapped_size = iova_length;
-
-	if (!msm_use_iommu()) {
-		data->iova_addr = info->handle;
-		return 0;
-	}
-
-	extra = iova_length - buffer->size;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -EINVAL;
-		goto out1;
-	}
-
-	ret = iommu_map_range(domain, data->iova_addr, table->sgl,
-				buffer->size, prot);
-
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	extra_iova_addr = data->iova_addr + buffer->size;
-	if (extra) {
-		unsigned long phys_addr = sg_phys(table->sgl);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	return ret;
-
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-out1:
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-out:
-	return ret;
-}
-
-
-void ion_secure_cma_unmap_iommu(struct ion_iommu_map *data)
-{
-	unsigned int domain_num;
-	unsigned int partition_num;
-	struct iommu_domain *domain;
-
-	if (!msm_use_iommu())
-		return;
-
-	domain_num = iommu_map_domain(data);
-	partition_num = iommu_map_partition(data);
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
-		return;
-	}
-
-	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-	return;
-}
-
-int ion_secure_cma_cache_ops(struct ion_heap *heap,
-			struct ion_buffer *buffer, void *vaddr,
-			unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	pr_info("%s: cache operations disallowed from secure heap %s\n",
-		__func__, heap->name);
-	return -EINVAL;
-}
-
 static int ion_secure_cma_print_debug(struct ion_heap *heap, struct seq_file *s,
 			const struct rb_root *mem_map)
 {
@@ -354,9 +249,6 @@
 	.map_user = ion_secure_cma_mmap,
 	.map_kernel = ion_secure_cma_map_kernel,
 	.unmap_kernel = ion_secure_cma_unmap_kernel,
-	.map_iommu = ion_secure_cma_map_iommu,
-	.unmap_iommu = ion_secure_cma_unmap_iommu,
-	.cache_op = ion_secure_cma_cache_ops,
 	.print_debug = ion_secure_cma_print_debug,
 	.secure_buffer = ion_cp_secure_buffer,
 	.unsecure_buffer = ion_cp_unsecure_buffer,
@@ -376,7 +268,6 @@
 	 * used to make the link with reserved CMA memory */
 	heap->priv = data->priv;
 	heap->type = ION_HEAP_TYPE_SECURE_DMA;
-	cma_heap_has_outer_cache = data->has_outer_cache;
 	return heap;
 }
 
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 88addab..f1868a8 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -67,10 +67,6 @@
  *			kernel space (un-cached).
  * @umap_count:	the total number of times this heap has been mapped in
  *		user space.
- * @iommu_iova: saved iova when mapping full heap at once.
- * @iommu_partition: partition used to map full heap.
- * @iommu_map_all:	Indicates whether we should map whole heap into IOMMU.
- * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
  * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
 */
 struct ion_cp_heap {
@@ -90,11 +86,6 @@
 	unsigned long kmap_cached_count;
 	unsigned long kmap_uncached_count;
 	unsigned long umap_count;
-	unsigned long iommu_iova[MAX_DOMAINS];
-	unsigned long iommu_partition[MAX_DOMAINS];
-	void *reserved_vrange;
-	int iommu_map_all;
-	int iommu_2x_map_domain;
 	unsigned int has_outer_cache;
 	atomic_t protect_cnt;
 	void *cpu_addr;
@@ -361,29 +352,6 @@
 	return offset;
 }
 
-static void iommu_unmap_all(unsigned long domain_num,
-			    struct ion_cp_heap *cp_heap)
-{
-	unsigned long left_to_unmap = cp_heap->total_size;
-	unsigned long page_size = SZ_64K;
-
-	struct iommu_domain *domain = msm_get_iommu_domain(domain_num);
-	if (domain) {
-		unsigned long temp_iova = cp_heap->iommu_iova[domain_num];
-
-		while (left_to_unmap) {
-			iommu_unmap(domain, temp_iova, page_size);
-			temp_iova += page_size;
-			left_to_unmap -= page_size;
-		}
-		if (domain_num == cp_heap->iommu_2x_map_domain)
-			msm_iommu_unmap_extra(domain, temp_iova,
-					      cp_heap->total_size, SZ_64K);
-	} else {
-		pr_err("Unable to get IOMMU domain %lu\n", domain_num);
-	}
-}
-
 void ion_cp_free(struct ion_heap *heap, ion_phys_addr_t addr,
 		       unsigned long size)
 {
@@ -401,25 +369,6 @@
 		cp_heap->heap_protected == HEAP_NOT_PROTECTED)
 		ion_on_last_free(heap);
 
-	/* Unmap everything if we previously mapped the whole heap at once. */
-	if (!cp_heap->allocated_bytes) {
-		unsigned int i;
-		for (i = 0; i < MAX_DOMAINS; ++i) {
-			if (cp_heap->iommu_iova[i]) {
-				unsigned long vaddr_len = cp_heap->total_size;
-
-				if (i == cp_heap->iommu_2x_map_domain)
-					vaddr_len <<= 1;
-				iommu_unmap_all(i, cp_heap);
-
-				msm_free_iova_address(cp_heap->iommu_iova[i], i,
-						cp_heap->iommu_partition[i],
-						vaddr_len);
-			}
-			cp_heap->iommu_iova[i] = 0;
-			cp_heap->iommu_partition[i] = 0;
-		}
-	}
 	mutex_unlock(&cp_heap->lock);
 }
 
@@ -674,91 +623,6 @@
 	mutex_unlock(&cp_heap->lock);
 }
 
-int ion_cp_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
-			void *vaddr, unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	void (*outer_cache_op)(phys_addr_t, phys_addr_t) = NULL;
-	struct ion_cp_heap *cp_heap =
-		container_of(heap, struct  ion_cp_heap, heap);
-	unsigned int size_to_vmap, total_size;
-	struct ion_cp_buffer *buf = buffer->priv_virt;
-	int i, j;
-	void *ptr = NULL;
-	ion_phys_addr_t buff_phys = buffer->priv_phys;
-
-	if (!vaddr) {
-		/*
-		 * Split the vmalloc space into smaller regions in
-		 * order to clean and/or invalidate the cache.
-		 */
-		size_to_vmap = (VMALLOC_END - VMALLOC_START)/8;
-		total_size = buffer->size;
-		for (i = 0; i < total_size; i += size_to_vmap) {
-			size_to_vmap = min(size_to_vmap, total_size - i);
-			for (j = 0; j < 10 && size_to_vmap; ++j) {
-				ptr = ioremap(buff_phys, size_to_vmap);
-				if (ptr) {
-					switch (cmd) {
-					case ION_IOC_CLEAN_CACHES:
-						dmac_clean_range(ptr,
-							ptr + size_to_vmap);
-						outer_cache_op =
-							outer_clean_range;
-						break;
-					case ION_IOC_INV_CACHES:
-						dmac_inv_range(ptr,
-							ptr + size_to_vmap);
-						outer_cache_op =
-							outer_inv_range;
-						break;
-					case ION_IOC_CLEAN_INV_CACHES:
-						dmac_flush_range(ptr,
-							ptr + size_to_vmap);
-						outer_cache_op =
-							outer_flush_range;
-						break;
-					default:
-						return -EINVAL;
-					}
-					buff_phys += size_to_vmap;
-					break;
-				} else {
-					size_to_vmap >>= 1;
-				}
-			}
-			if (!ptr) {
-				pr_err("Couldn't io-remap the memory\n");
-				return -EINVAL;
-			}
-			iounmap(ptr);
-		}
-	} else {
-		switch (cmd) {
-		case ION_IOC_CLEAN_CACHES:
-			dmac_clean_range(vaddr, vaddr + length);
-			outer_cache_op = outer_clean_range;
-			break;
-		case ION_IOC_INV_CACHES:
-			dmac_inv_range(vaddr, vaddr + length);
-			outer_cache_op = outer_inv_range;
-			break;
-		case ION_IOC_CLEAN_INV_CACHES:
-			dmac_flush_range(vaddr, vaddr + length);
-			outer_cache_op = outer_flush_range;
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	if (cp_heap->has_outer_cache) {
-		unsigned long pstart = buf->buffer + offset;
-		outer_cache_op(pstart, pstart + length);
-	}
-	return 0;
-}
-
 static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
 			      const struct rb_root *mem_map)
 {
@@ -859,205 +723,6 @@
 	return ret_value;
 }
 
-static int iommu_map_all(unsigned long domain_num, struct ion_cp_heap *cp_heap,
-			int partition, unsigned long prot)
-{
-	unsigned long left_to_map = cp_heap->total_size;
-	unsigned long page_size = SZ_64K;
-	int ret_value = 0;
-	unsigned long virt_addr_len = cp_heap->total_size;
-	struct iommu_domain *domain = msm_get_iommu_domain(domain_num);
-
-	/* If we are mapping into the video domain we need to map twice the
-	 * size of the heap to account for prefetch issue in video core.
-	 */
-	if (domain_num == cp_heap->iommu_2x_map_domain)
-		virt_addr_len <<= 1;
-
-	if (cp_heap->total_size & (SZ_64K-1)) {
-		pr_err("Heap size is not aligned to 64K, cannot map into IOMMU\n");
-		ret_value = -EINVAL;
-	}
-	if (cp_heap->base & (SZ_64K-1)) {
-		pr_err("Heap physical address is not aligned to 64K, cannot map into IOMMU\n");
-		ret_value = -EINVAL;
-	}
-	if (!ret_value && domain) {
-		unsigned long temp_phys = cp_heap->base;
-		unsigned long temp_iova;
-
-		ret_value = msm_allocate_iova_address(domain_num, partition,
-						virt_addr_len, SZ_64K,
-						&temp_iova);
-
-		if (ret_value) {
-			pr_err("%s: could not allocate iova from domain %lu, partition %d\n",
-				__func__, domain_num, partition);
-			goto out;
-		}
-		cp_heap->iommu_iova[domain_num] = temp_iova;
-
-		while (left_to_map) {
-			int ret = iommu_map(domain, temp_iova, temp_phys,
-					page_size, prot);
-			if (ret) {
-				pr_err("%s: could not map %lx in domain %p, error: %d\n",
-					__func__, temp_iova, domain, ret);
-				ret_value = -EAGAIN;
-				goto free_iova;
-			}
-			temp_iova += page_size;
-			temp_phys += page_size;
-			left_to_map -= page_size;
-		}
-		if (domain_num == cp_heap->iommu_2x_map_domain)
-			ret_value = msm_iommu_map_extra(domain, temp_iova,
-							cp_heap->base,
-							cp_heap->total_size,
-							SZ_64K, prot);
-		if (ret_value)
-			goto free_iova;
-	} else {
-		pr_err("Unable to get IOMMU domain %lu\n", domain_num);
-		ret_value = -ENOMEM;
-	}
-	goto out;
-
-free_iova:
-	msm_free_iova_address(cp_heap->iommu_iova[domain_num], domain_num,
-			      partition, virt_addr_len);
-out:
-	return ret_value;
-}
-
-static int ion_cp_heap_map_iommu(struct ion_buffer *buffer,
-				struct ion_iommu_map *data,
-				unsigned int domain_num,
-				unsigned int partition_num,
-				unsigned long align,
-				unsigned long iova_length,
-				unsigned long flags)
-{
-	struct iommu_domain *domain;
-	int ret = 0;
-	unsigned long extra;
-	struct ion_cp_heap *cp_heap =
-		container_of(buffer->heap, struct ion_cp_heap, heap);
-	int prot = IOMMU_WRITE | IOMMU_READ;
-	struct ion_cp_buffer *buf = buffer->priv_virt;
-	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
-
-	data->mapped_size = iova_length;
-
-	if (!msm_use_iommu()) {
-		data->iova_addr = buf->buffer;
-		return 0;
-	}
-
-	if (cp_heap->iommu_iova[domain_num]) {
-		/* Already mapped. */
-		unsigned long offset = buf->buffer - cp_heap->base;
-		data->iova_addr = cp_heap->iommu_iova[domain_num] + offset;
-		return 0;
-	} else if (cp_heap->iommu_map_all) {
-		ret = iommu_map_all(domain_num, cp_heap, partition_num, prot);
-		if (!ret) {
-			unsigned long offset =
-					buf->buffer - cp_heap->base;
-			data->iova_addr =
-				cp_heap->iommu_iova[domain_num] + offset;
-			cp_heap->iommu_partition[domain_num] = partition_num;
-			/*
-			clear delayed map flag so that we don't interfere
-			with this feature (we are already delaying).
-			*/
-			data->flags &= ~ION_IOMMU_UNMAP_DELAYED;
-			return 0;
-		} else {
-			cp_heap->iommu_iova[domain_num] = 0;
-			cp_heap->iommu_partition[domain_num] = 0;
-			return ret;
-		}
-	}
-
-	extra = iova_length - buffer->size;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -ENOMEM;
-		goto out1;
-	}
-
-	ret = iommu_map_range(domain, data->iova_addr, buffer->sg_table->sgl,
-			      buffer->size, prot);
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	if (extra) {
-		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		unsigned long phys_addr = sg_phys(buffer->sg_table->sgl);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	return ret;
-
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-out1:
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-out:
-	return ret;
-}
-
-static void ion_cp_heap_unmap_iommu(struct ion_iommu_map *data)
-{
-	unsigned int domain_num;
-	unsigned int partition_num;
-	struct iommu_domain *domain;
-	struct ion_cp_heap *cp_heap =
-		container_of(data->buffer->heap, struct ion_cp_heap, heap);
-
-	if (!msm_use_iommu())
-		return;
-
-
-	domain_num = iommu_map_domain(data);
-
-	/* If we are mapping everything we'll wait to unmap until everything
-	   is freed. */
-	if (cp_heap->iommu_iova[domain_num])
-		return;
-
-	partition_num = iommu_map_partition(data);
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
-		return;
-	}
-
-	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-	return;
-}
-
 static struct ion_heap_ops cp_heap_ops = {
 	.allocate = ion_cp_heap_allocate,
 	.free = ion_cp_heap_free,
@@ -1068,12 +733,9 @@
 	.unmap_kernel = ion_cp_heap_unmap_kernel,
 	.map_dma = ion_cp_heap_map_dma,
 	.unmap_dma = ion_cp_heap_unmap_dma,
-	.cache_op = ion_cp_cache_ops,
 	.print_debug = ion_cp_print_debug,
 	.secure_heap = ion_cp_secure_heap,
 	.unsecure_heap = ion_cp_unsecure_heap,
-	.map_iommu = ion_cp_heap_map_iommu,
-	.unmap_iommu = ion_cp_heap_unmap_iommu,
 	.secure_buffer = ion_cp_secure_buffer,
 	.unsecure_buffer = ion_cp_unsecure_buffer,
 };
@@ -1120,10 +782,6 @@
 		if (extra_data->release_region)
 			cp_heap->heap_release_region =
 				extra_data->release_region;
-		cp_heap->iommu_map_all =
-				extra_data->iommu_map_all;
-		cp_heap->iommu_2x_map_domain =
-				extra_data->iommu_2x_map_domain;
 		cp_heap->cma = extra_data->is_cma;
 		cp_heap->allow_non_secure_allocation =
 			extra_data->allow_nonsecure_alloc;
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 512ebf3..ca29016 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -30,7 +30,6 @@
 
 struct ion_iommu_heap {
 	struct ion_heap heap;
-	unsigned int has_outer_cache;
 };
 
 /*
@@ -315,157 +314,6 @@
 	return 0;
 }
 
-int ion_iommu_heap_map_iommu(struct ion_buffer *buffer,
-					struct ion_iommu_map *data,
-					unsigned int domain_num,
-					unsigned int partition_num,
-					unsigned long align,
-					unsigned long iova_length,
-					unsigned long flags)
-{
-	struct iommu_domain *domain;
-	int ret = 0;
-	unsigned long extra;
-	int prot = IOMMU_WRITE | IOMMU_READ;
-	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
-
-	BUG_ON(!msm_use_iommu());
-
-	data->mapped_size = iova_length;
-	extra = iova_length - buffer->size;
-
-	/* Use the biggest alignment to allow bigger IOMMU mappings.
-	 * Use the first entry since the first entry will always be the
-	 * biggest entry. To take advantage of bigger mapping sizes both the
-	 * VA and PA addresses have to be aligned to the biggest size.
-	 */
-	if (buffer->sg_table->sgl->length > align)
-		align = buffer->sg_table->sgl->length;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -ENOMEM;
-		goto out1;
-	}
-
-	ret = iommu_map_range(domain, data->iova_addr,
-			      buffer->sg_table->sgl,
-			      buffer->size, prot);
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	if (extra) {
-		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		unsigned long phys_addr = sg_phys(buffer->sg_table->sgl);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	return ret;
-
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-out1:
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				buffer->size);
-
-out:
-
-	return ret;
-}
-
-void ion_iommu_heap_unmap_iommu(struct ion_iommu_map *data)
-{
-	unsigned int domain_num;
-	unsigned int partition_num;
-	struct iommu_domain *domain;
-
-	BUG_ON(!msm_use_iommu());
-
-	domain_num = iommu_map_domain(data);
-	partition_num = iommu_map_partition(data);
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
-		return;
-	}
-
-	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-	return;
-}
-
-static int ion_iommu_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
-			void *vaddr, unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
-	struct ion_iommu_heap *iommu_heap =
-	     container_of(heap, struct  ion_iommu_heap, heap);
-
-	switch (cmd) {
-	case ION_IOC_CLEAN_CACHES:
-		if (!vaddr)
-			dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_TO_DEVICE);
-		else
-			dmac_clean_range(vaddr, vaddr + length);
-		outer_cache_op = outer_clean_range;
-		break;
-	case ION_IOC_INV_CACHES:
-		if (!vaddr)
-			dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_FROM_DEVICE);
-		else
-			dmac_inv_range(vaddr, vaddr + length);
-		outer_cache_op = outer_inv_range;
-		break;
-	case ION_IOC_CLEAN_INV_CACHES:
-		if (!vaddr) {
-			dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_TO_DEVICE);
-			dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_FROM_DEVICE);
-		} else {
-			dmac_flush_range(vaddr, vaddr + length);
-		}
-		outer_cache_op = outer_flush_range;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (iommu_heap->has_outer_cache) {
-		unsigned long pstart;
-		unsigned int i;
-		struct ion_iommu_priv_data *data = buffer->priv_virt;
-		if (!data)
-			return -ENOMEM;
-
-		for (i = 0; i < data->nrpages; ++i) {
-			pstart = page_to_phys(data->pages[i]);
-			outer_cache_op(pstart, pstart + PAGE_SIZE);
-		}
-	}
-	return 0;
-}
-
 static struct sg_table *ion_iommu_heap_map_dma(struct ion_heap *heap,
 					      struct ion_buffer *buffer)
 {
@@ -483,9 +331,6 @@
 	.map_user = ion_iommu_heap_map_user,
 	.map_kernel = ion_iommu_heap_map_kernel,
 	.unmap_kernel = ion_iommu_heap_unmap_kernel,
-	.map_iommu = ion_iommu_heap_map_iommu,
-	.unmap_iommu = ion_iommu_heap_unmap_iommu,
-	.cache_op = ion_iommu_cache_ops,
 	.map_dma = ion_iommu_heap_map_dma,
 	.unmap_dma = ion_iommu_heap_unmap_dma,
 };
@@ -500,7 +345,6 @@
 
 	iommu_heap->heap.ops = &iommu_heap_ops;
 	iommu_heap->heap.type = ION_HEAP_TYPE_IOMMU;
-	iommu_heap->has_outer_cache = heap_data->has_outer_cache;
 
 	return &iommu_heap->heap;
 }
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 8d45f9d..71527ae 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -65,8 +65,6 @@
 	struct sg_table *sg_table;
 	unsigned long *dirty;
 	struct list_head vmas;
-	unsigned int iommu_map_cnt;
-	struct rb_root iommu_maps;
 	int marked;
 };
 
@@ -98,17 +96,6 @@
 	int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer,
 			 struct vm_area_struct *vma);
 	void (*unmap_user) (struct ion_heap *mapper, struct ion_buffer *buffer);
-	int (*cache_op)(struct ion_heap *heap, struct ion_buffer *buffer,
-			void *vaddr, unsigned int offset,
-			unsigned int length, unsigned int cmd);
-	int (*map_iommu)(struct ion_buffer *buffer,
-				struct ion_iommu_map *map_data,
-				unsigned int domain_num,
-				unsigned int partition_num,
-				unsigned long align,
-				unsigned long iova_length,
-				unsigned long flags);
-	void (*unmap_iommu)(struct ion_iommu_map *data);
 	int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
 			   const struct rb_root *mem_map);
 	int (*secure_heap)(struct ion_heap *heap, int version, void *data);
diff --git a/drivers/gpu/ion/ion_removed_heap.c b/drivers/gpu/ion/ion_removed_heap.c
new file mode 100644
index 0000000..84d8d37
--- /dev/null
+++ b/drivers/gpu/ion/ion_removed_heap.c
@@ -0,0 +1,353 @@
+/*
+ * drivers/gpu/ion/ion_removed_heap.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/spinlock.h>
+
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/seq_file.h>
+#include "ion_priv.h"
+
+#include <asm/mach/map.h>
+#include <asm/cacheflush.h>
+#include <linux/msm_ion.h>
+
+struct ion_removed_heap {
+	struct ion_heap heap;
+	struct gen_pool *pool;
+	ion_phys_addr_t base;
+	unsigned long allocated_bytes;
+	unsigned long total_size;
+	int (*request_region)(void *);
+	int (*release_region)(void *);
+	atomic_t map_count;
+	void *bus_id;
+};
+
+ion_phys_addr_t ion_removed_allocate(struct ion_heap *heap,
+				      unsigned long size,
+				      unsigned long align)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+	unsigned long offset = gen_pool_alloc_aligned(removed_heap->pool,
+							size, ilog2(align));
+
+	if (!offset) {
+		if ((removed_heap->total_size -
+		      removed_heap->allocated_bytes) >= size)
+			pr_debug("%s: heap %s has enough memory (%lx) but the allocation of size %lx still failed. Memory is probably fragmented.",
+				__func__, heap->name,
+				removed_heap->total_size -
+				removed_heap->allocated_bytes, size);
+		return ION_CARVEOUT_ALLOCATE_FAIL;
+	}
+
+	removed_heap->allocated_bytes += size;
+	return offset;
+}
+
+void ion_removed_free(struct ion_heap *heap, ion_phys_addr_t addr,
+		       unsigned long size)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+
+	if (addr == ION_CARVEOUT_ALLOCATE_FAIL)
+		return;
+	gen_pool_free(removed_heap->pool, addr, size);
+	removed_heap->allocated_bytes -= size;
+}
+
+static int ion_removed_heap_phys(struct ion_heap *heap,
+				  struct ion_buffer *buffer,
+				  ion_phys_addr_t *addr, size_t *len)
+{
+	*addr = buffer->priv_phys;
+	*len = buffer->size;
+	return 0;
+}
+
+static int ion_removed_heap_allocate(struct ion_heap *heap,
+				      struct ion_buffer *buffer,
+				      unsigned long size, unsigned long align,
+				      unsigned long flags)
+{
+	buffer->priv_phys = ion_removed_allocate(heap, size, align);
+	return buffer->priv_phys == ION_CARVEOUT_ALLOCATE_FAIL ? -ENOMEM : 0;
+}
+
+static void ion_removed_heap_free(struct ion_buffer *buffer)
+{
+	struct ion_heap *heap = buffer->heap;
+
+	ion_removed_free(heap, buffer->priv_phys, buffer->size);
+	buffer->priv_phys = ION_CARVEOUT_ALLOCATE_FAIL;
+}
+
+struct sg_table *ion_removed_heap_map_dma(struct ion_heap *heap,
+					      struct ion_buffer *buffer)
+{
+	struct sg_table *table;
+	int ret;
+
+	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table)
+		return ERR_PTR(-ENOMEM);
+
+	ret = sg_alloc_table(table, 1, GFP_KERNEL);
+	if (ret)
+		goto err0;
+
+	table->sgl->length = buffer->size;
+	table->sgl->offset = 0;
+	table->sgl->dma_address = buffer->priv_phys;
+
+	return table;
+
+err0:
+	kfree(table);
+	return ERR_PTR(ret);
+}
+
+void ion_removed_heap_unmap_dma(struct ion_heap *heap,
+				 struct ion_buffer *buffer)
+{
+	if (buffer->sg_table)
+		sg_free_table(buffer->sg_table);
+	kfree(buffer->sg_table);
+	buffer->sg_table = 0;
+}
+
+static int ion_removed_request_region(struct ion_removed_heap *removed_heap)
+{
+	int ret_value = 0;
+	if (atomic_inc_return(&removed_heap->map_count) == 1) {
+		if (removed_heap->request_region) {
+			ret_value = removed_heap->request_region(
+						removed_heap->bus_id);
+			if (ret_value) {
+				pr_err("Unable to request SMI region");
+				atomic_dec(&removed_heap->map_count);
+			}
+		}
+	}
+	return ret_value;
+}
+
+static int ion_removed_release_region(struct ion_removed_heap *removed_heap)
+{
+	int ret_value = 0;
+	if (atomic_dec_and_test(&removed_heap->map_count)) {
+		if (removed_heap->release_region) {
+			ret_value = removed_heap->release_region(
+						removed_heap->bus_id);
+			if (ret_value)
+				pr_err("Unable to release SMI region");
+		}
+	}
+	return ret_value;
+}
+
+void *ion_removed_heap_map_kernel(struct ion_heap *heap,
+				   struct ion_buffer *buffer)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+	void *ret_value;
+
+	if (ion_removed_request_region(removed_heap))
+		return NULL;
+
+	if (ION_IS_CACHED(buffer->flags))
+		ret_value = ioremap_cached(buffer->priv_phys, buffer->size);
+	else
+		ret_value = ioremap(buffer->priv_phys, buffer->size);
+
+	if (!ret_value)
+		ion_removed_release_region(removed_heap);
+	return ret_value;
+}
+
+void ion_removed_heap_unmap_kernel(struct ion_heap *heap,
+				    struct ion_buffer *buffer)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+
+	__arm_iounmap(buffer->vaddr);
+	buffer->vaddr = NULL;
+
+	ion_removed_release_region(removed_heap);
+	return;
+}
+
+int ion_removed_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+			       struct vm_area_struct *vma)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+	int ret_value = 0;
+
+	if (ion_removed_request_region(removed_heap))
+		return -EINVAL;
+
+	if (!ION_IS_CACHED(buffer->flags))
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	ret_value =  remap_pfn_range(vma, vma->vm_start,
+			__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+			vma->vm_end - vma->vm_start,
+			vma->vm_page_prot);
+
+	if (ret_value)
+		ion_removed_release_region(removed_heap);
+	return ret_value;
+}
+
+void ion_removed_heap_unmap_user(struct ion_heap *heap,
+				    struct ion_buffer *buffer)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+	ion_removed_release_region(removed_heap);
+}
+
+static int ion_removed_print_debug(struct ion_heap *heap, struct seq_file *s,
+				    const struct rb_root *mem_map)
+{
+	struct ion_removed_heap *removed_heap =
+		container_of(heap, struct ion_removed_heap, heap);
+
+	seq_printf(s, "total bytes currently allocated: %lx\n",
+		removed_heap->allocated_bytes);
+	seq_printf(s, "total heap size: %lx\n", removed_heap->total_size);
+
+	if (mem_map) {
+		unsigned long base = removed_heap->base;
+		unsigned long size = removed_heap->total_size;
+		unsigned long end = base+size;
+		unsigned long last_end = base;
+		struct rb_node *n;
+
+		seq_printf(s, "\nMemory Map\n");
+		seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+			   "client", "start address", "end address",
+			   "size (hex)");
+
+		for (n = rb_first(mem_map); n; n = rb_next(n)) {
+			struct mem_map_data *data =
+					rb_entry(n, struct mem_map_data, node);
+			const char *client_name = "(null)";
+
+			if (last_end < data->addr) {
+				phys_addr_t da;
+
+				da = data->addr-1;
+				seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+					   "FREE", &last_end, &da,
+					   data->addr-last_end,
+					   data->addr-last_end);
+			}
+
+			if (data->client_name)
+				client_name = data->client_name;
+
+			seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+				   client_name, &data->addr,
+				   &data->addr_end,
+				   data->size, data->size);
+			last_end = data->addr_end+1;
+		}
+		if (last_end < end) {
+			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+				last_end, end-1, end-last_end, end-last_end);
+		}
+	}
+	return 0;
+}
+
+static struct ion_heap_ops removed_heap_ops = {
+	.allocate = ion_removed_heap_allocate,
+	.free = ion_removed_heap_free,
+	.phys = ion_removed_heap_phys,
+	.map_user = ion_removed_heap_map_user,
+	.map_kernel = ion_removed_heap_map_kernel,
+	.unmap_user = ion_removed_heap_unmap_user,
+	.unmap_kernel = ion_removed_heap_unmap_kernel,
+	.map_dma = ion_removed_heap_map_dma,
+	.unmap_dma = ion_removed_heap_unmap_dma,
+	.print_debug = ion_removed_print_debug,
+};
+
+struct ion_heap *ion_removed_heap_create(struct ion_platform_heap *heap_data)
+{
+	struct ion_removed_heap *removed_heap;
+	int ret;
+
+	removed_heap = kzalloc(sizeof(struct ion_removed_heap), GFP_KERNEL);
+	if (!removed_heap)
+		return ERR_PTR(-ENOMEM);
+
+	removed_heap->pool = gen_pool_create(12, -1);
+	if (!removed_heap->pool) {
+		kfree(removed_heap);
+		return ERR_PTR(-ENOMEM);
+	}
+	removed_heap->base = heap_data->base;
+	ret = gen_pool_add(removed_heap->pool, removed_heap->base,
+			heap_data->size, -1);
+	if (ret < 0) {
+		gen_pool_destroy(removed_heap->pool);
+		kfree(removed_heap);
+		return ERR_PTR(-EINVAL);
+	}
+	removed_heap->heap.ops = &removed_heap_ops;
+	removed_heap->heap.type = ION_HEAP_TYPE_REMOVED;
+	removed_heap->allocated_bytes = 0;
+	removed_heap->total_size = heap_data->size;
+
+	if (heap_data->extra_data) {
+		struct ion_co_heap_pdata *extra_data =
+				heap_data->extra_data;
+
+		if (extra_data->setup_region)
+			removed_heap->bus_id = extra_data->setup_region();
+		if (extra_data->request_region)
+			removed_heap->request_region =
+					extra_data->request_region;
+		if (extra_data->release_region)
+			removed_heap->release_region =
+					extra_data->release_region;
+	}
+	return &removed_heap->heap;
+}
+
+void ion_removed_heap_destroy(struct ion_heap *heap)
+{
+	struct ion_removed_heap *removed_heap =
+	     container_of(heap, struct  ion_removed_heap, heap);
+
+	gen_pool_destroy(removed_heap->pool);
+	kfree(removed_heap);
+	removed_heap = NULL;
+}
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index ceb30a4..af7f04b 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -24,9 +24,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/iommu.h>
 #include <linux/seq_file.h>
-#include <mach/iommu_domains.h>
 #include "ion_priv.h"
 #include <mach/memory.h>
 #include <asm/cacheflush.h>
@@ -35,8 +33,6 @@
 
 static atomic_t system_heap_allocated;
 static atomic_t system_contig_heap_allocated;
-static unsigned int system_heap_has_outer_cache;
-static unsigned int system_heap_contig_has_outer_cache;
 
 struct page_info {
 	struct page *page;
@@ -210,32 +206,6 @@
 	vunmap(buffer->vaddr);
 }
 
-void ion_system_heap_unmap_iommu(struct ion_iommu_map *data)
-{
-	unsigned int domain_num;
-	unsigned int partition_num;
-	struct iommu_domain *domain;
-
-	if (!msm_use_iommu())
-		return;
-
-	domain_num = iommu_map_domain(data);
-	partition_num = iommu_map_partition(data);
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
-		return;
-	}
-
-	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-
-	return;
-}
-
 int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 			     struct vm_area_struct *vma)
 {
@@ -262,66 +232,6 @@
 	return 0;
 }
 
-int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
-			void *vaddr, unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
-
-	switch (cmd) {
-	case ION_IOC_CLEAN_CACHES:
-		if (!vaddr)
-			dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_TO_DEVICE);
-		else
-			dmac_clean_range(vaddr, vaddr + length);
-		outer_cache_op = outer_clean_range;
-		break;
-	case ION_IOC_INV_CACHES:
-		if (!vaddr)
-			dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_FROM_DEVICE);
-		else
-			dmac_inv_range(vaddr, vaddr + length);
-		outer_cache_op = outer_inv_range;
-		break;
-	case ION_IOC_CLEAN_INV_CACHES:
-		if (!vaddr) {
-			dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_TO_DEVICE);
-			dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl,
-				buffer->sg_table->nents, DMA_FROM_DEVICE);
-		} else {
-			dmac_flush_range(vaddr, vaddr + length);
-		}
-		outer_cache_op = outer_flush_range;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (system_heap_has_outer_cache) {
-		unsigned long pstart;
-		struct sg_table *table = buffer->priv_virt;
-		struct scatterlist *sg;
-		int i;
-		for_each_sg(table->sgl, sg, table->nents, i) {
-			struct page *page = sg_page(sg);
-			pstart = page_to_phys(page);
-			/*
-			 * If page -> phys is returning NULL, something
-			 * has really gone wrong...
-			 */
-			if (!pstart) {
-				WARN(1, "Could not translate virtual address to physical address\n");
-				return -EINVAL;
-			}
-			outer_cache_op(pstart, pstart + PAGE_SIZE);
-		}
-	}
-	return 0;
-}
-
 static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
 				  const struct rb_root *unused)
 {
@@ -331,81 +241,6 @@
 	return 0;
 }
 
-int ion_system_heap_map_iommu(struct ion_buffer *buffer,
-				struct ion_iommu_map *data,
-				unsigned int domain_num,
-				unsigned int partition_num,
-				unsigned long align,
-				unsigned long iova_length,
-				unsigned long flags)
-{
-	int ret = 0;
-	struct iommu_domain *domain;
-	unsigned long extra;
-	unsigned long extra_iova_addr;
-	struct sg_table *table = buffer->priv_virt;
-	int prot = IOMMU_WRITE | IOMMU_READ;
-	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
-
-	if (!ION_IS_CACHED(flags))
-		return -EINVAL;
-
-	if (!msm_use_iommu())
-		return -EINVAL;
-
-	data->mapped_size = iova_length;
-	extra = iova_length - buffer->size;
-
-	/* Use the biggest alignment to allow bigger IOMMU mappings.
-	 * Use the first entry since the first entry will always be the
-	 * biggest entry. To take advantage of bigger mapping sizes both the
-	 * VA and PA addresses have to be aligned to the biggest size.
-	 */
-	if (table->sgl->length > align)
-		align = table->sgl->length;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -ENOMEM;
-		goto out1;
-	}
-
-	ret = iommu_map_range(domain, data->iova_addr, table->sgl,
-			      buffer->size, prot);
-
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	extra_iova_addr = data->iova_addr + buffer->size;
-	if (extra) {
-		unsigned long phys_addr = sg_phys(table->sgl);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	return ret;
-
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-out1:
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				data->mapped_size);
-out:
-	return ret;
-}
-
 static struct ion_heap_ops vmalloc_ops = {
 	.allocate = ion_system_heap_allocate,
 	.free = ion_system_heap_free,
@@ -414,10 +249,7 @@
 	.map_kernel = ion_system_heap_map_kernel,
 	.unmap_kernel = ion_system_heap_unmap_kernel,
 	.map_user = ion_system_heap_map_user,
-	.cache_op = ion_system_heap_cache_ops,
 	.print_debug = ion_system_print_debug,
-	.map_iommu = ion_system_heap_map_iommu,
-	.unmap_iommu = ion_system_heap_unmap_iommu,
 };
 
 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
@@ -429,7 +261,6 @@
 		return ERR_PTR(-ENOMEM);
 	heap->ops = &vmalloc_ops;
 	heap->type = ION_HEAP_TYPE_SYSTEM;
-	system_heap_has_outer_cache = pheap->has_outer_cache;
 	return heap;
 }
 
@@ -508,46 +339,6 @@
 	}
 }
 
-int ion_system_contig_heap_cache_ops(struct ion_heap *heap,
-			struct ion_buffer *buffer, void *vaddr,
-			unsigned int offset, unsigned int length,
-			unsigned int cmd)
-{
-	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
-
-	switch (cmd) {
-	case ION_IOC_CLEAN_CACHES:
-		dmac_clean_range(vaddr, vaddr + length);
-		outer_cache_op = outer_clean_range;
-		break;
-	case ION_IOC_INV_CACHES:
-		dmac_inv_range(vaddr, vaddr + length);
-		outer_cache_op = outer_inv_range;
-		break;
-	case ION_IOC_CLEAN_INV_CACHES:
-		dmac_flush_range(vaddr, vaddr + length);
-		outer_cache_op = outer_flush_range;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (system_heap_contig_has_outer_cache) {
-		unsigned long pstart;
-
-		pstart = virt_to_phys(buffer->priv_virt) + offset;
-		if (!pstart) {
-			WARN(1, "Could not do virt to phys translation on %p\n",
-				buffer->priv_virt);
-			return -EINVAL;
-		}
-
-		outer_cache_op(pstart, pstart + PAGE_SIZE);
-	}
-
-	return 0;
-}
-
 static int ion_system_contig_print_debug(struct ion_heap *heap,
 					 struct seq_file *s,
 					 const struct rb_root *unused)
@@ -558,84 +349,6 @@
 	return 0;
 }
 
-int ion_system_contig_heap_map_iommu(struct ion_buffer *buffer,
-				struct ion_iommu_map *data,
-				unsigned int domain_num,
-				unsigned int partition_num,
-				unsigned long align,
-				unsigned long iova_length,
-				unsigned long flags)
-{
-	int ret = 0;
-	struct iommu_domain *domain;
-	unsigned long extra;
-	struct scatterlist *sglist = 0;
-	struct page *page = 0;
-	int prot = IOMMU_WRITE | IOMMU_READ;
-	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
-
-	if (!ION_IS_CACHED(flags))
-		return -EINVAL;
-
-	if (!msm_use_iommu()) {
-		data->iova_addr = virt_to_phys(buffer->vaddr);
-		return 0;
-	}
-
-	data->mapped_size = iova_length;
-	extra = iova_length - buffer->size;
-
-	ret = msm_allocate_iova_address(domain_num, partition_num,
-						data->mapped_size, align,
-						&data->iova_addr);
-
-	if (ret)
-		goto out;
-
-	domain = msm_get_iommu_domain(domain_num);
-
-	if (!domain) {
-		ret = -ENOMEM;
-		goto out1;
-	}
-	page = virt_to_page(buffer->vaddr);
-
-	sglist = vmalloc(sizeof(*sglist));
-	if (!sglist)
-		goto out1;
-
-	sg_init_table(sglist, 1);
-	sg_set_page(sglist, page, buffer->size, 0);
-
-	ret = iommu_map_range(domain, data->iova_addr, sglist,
-			      buffer->size, prot);
-	if (ret) {
-		pr_err("%s: could not map %lx in domain %p\n",
-			__func__, data->iova_addr, domain);
-		goto out1;
-	}
-
-	if (extra) {
-		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		unsigned long phys_addr = sg_phys(sglist);
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
-					extra, SZ_4K, prot);
-		if (ret)
-			goto out2;
-	}
-	vfree(sglist);
-	return ret;
-out2:
-	iommu_unmap_range(domain, data->iova_addr, buffer->size);
-
-out1:
-	vfree(sglist);
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-						data->mapped_size);
-out:
-	return ret;
-}
-
 void *ion_system_contig_heap_map_kernel(struct ion_heap *heap,
 	struct ion_buffer *buffer)
 {
@@ -657,10 +370,7 @@
 	.map_kernel = ion_system_contig_heap_map_kernel,
 	.unmap_kernel = ion_system_contig_heap_unmap_kernel,
 	.map_user = ion_system_contig_heap_map_user,
-	.cache_op = ion_system_contig_heap_cache_ops,
 	.print_debug = ion_system_contig_print_debug,
-	.map_iommu = ion_system_contig_heap_map_iommu,
-	.unmap_iommu = ion_system_heap_unmap_iommu,
 };
 
 struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *pheap)
@@ -672,7 +382,6 @@
 		return ERR_PTR(-ENOMEM);
 	heap->ops = &kmalloc_ops;
 	heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG;
-	system_heap_contig_has_outer_cache = pheap->has_outer_cache;
 	return heap;
 }
 
diff --git a/drivers/gpu/ion/msm/Makefile b/drivers/gpu/ion/msm/Makefile
index 1893405..becdb02 100644
--- a/drivers/gpu/ion/msm/Makefile
+++ b/drivers/gpu/ion/msm/Makefile
@@ -1 +1 @@
-obj-y += msm_ion.o ion_cp_common.o
+obj-y += msm_ion.o ion_cp_common.o ion_iommu_map.o
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
new file mode 100644
index 0000000..ae4ae37
--- /dev/null
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -0,0 +1,538 @@
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/export.h>
+#include <linux/iommu.h>
+#include <linux/ion.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+#include <mach/iommu_domains.h>
+
+enum {
+	DI_PARTITION_NUM = 0,
+	DI_DOMAIN_NUM = 1,
+	DI_MAX,
+};
+
+#define iommu_map_domain(__m)           ((__m)->domain_info[1])
+#define iommu_map_partition(__m)        ((__m)->domain_info[0])
+
+/**
+ * struct ion_iommu_map - represents a mapping of an ion buffer to an iommu
+ * @iova_addr - iommu virtual address
+ * @node - rb node to exist in the buffer's tree of iommu mappings
+ * @domain_info - contains the partition number and domain number
+ *		domain_info[1] = domain number
+ *		domain_info[0] = partition number
+ * @ref - for reference counting this mapping
+ * @mapped_size - size of the iova space mapped
+ *		(may not be the same as the buffer size)
+ * @flags - iommu domain/partition specific flags.
+ *
+ * Represents a mapping of one ion buffer to a particular iommu domain
+ * and address range. There may exist other mappings of this buffer in
+ * different domains or address ranges. All mappings will have the same
+ * cacheability and security.
+ */
+struct ion_iommu_map {
+	unsigned long iova_addr;
+	struct rb_node node;
+	union {
+		int domain_info[DI_MAX];
+		uint64_t key;
+	};
+	struct ion_iommu_meta *meta;
+	struct kref ref;
+	int mapped_size;
+	unsigned long flags;
+};
+
+
+struct ion_iommu_meta {
+	struct rb_node node;
+	struct ion_handle *handle;
+	struct rb_root iommu_maps;
+	struct kref ref;
+	struct sg_table *table;
+	unsigned long size;
+	struct mutex lock;
+};
+
+static struct rb_root iommu_root;
+DEFINE_MUTEX(msm_iommu_map_mutex);
+
+static void ion_iommu_meta_add(struct ion_iommu_meta *meta)
+{
+	struct rb_root *root = &iommu_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct ion_iommu_meta *entry;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct ion_iommu_meta, node);
+
+		if (meta->handle < entry->handle) {
+			p = &(*p)->rb_left;
+		} else if (meta->handle > entry->handle) {
+			p = &(*p)->rb_right;
+		} else {
+			pr_err("%s: handle %p already exists\n", __func__,
+				entry->handle);
+			BUG();
+		}
+	}
+
+	rb_link_node(&meta->node, parent, p);
+	rb_insert_color(&meta->node, root);
+}
+
+
+static struct ion_iommu_meta *ion_iommu_meta_lookup(struct ion_handle *handle)
+{
+	struct rb_root *root = &iommu_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct ion_iommu_meta *entry = NULL;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct ion_iommu_meta, node);
+
+		if (handle < entry->handle)
+			p = &(*p)->rb_left;
+		else if (handle > entry->handle)
+			p = &(*p)->rb_right;
+		else
+			return entry;
+	}
+
+	return NULL;
+}
+
+
+
+static void ion_iommu_add(struct ion_iommu_meta *meta,
+			struct ion_iommu_map *iommu)
+{
+	struct rb_node **p = &meta->iommu_maps.rb_node;
+	struct rb_node *parent = NULL;
+	struct ion_iommu_map *entry;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct ion_iommu_map, node);
+
+		if (iommu->key < entry->key) {
+			p = &(*p)->rb_left;
+		} else if (iommu->key > entry->key) {
+			p = &(*p)->rb_right;
+		} else {
+			pr_err("%s: handle %p already has mapping for domain %d and partition %d\n",
+				__func__,
+				meta->handle,
+				iommu_map_domain(iommu),
+				iommu_map_partition(iommu));
+			BUG();
+		}
+	}
+
+	rb_link_node(&iommu->node, parent, p);
+	rb_insert_color(&iommu->node, &meta->iommu_maps);
+}
+
+
+static struct ion_iommu_map *ion_iommu_lookup(
+					struct ion_iommu_meta *meta,
+					unsigned int domain_no,
+					unsigned int partition_no)
+{
+	struct rb_node **p = &meta->iommu_maps.rb_node;
+	struct rb_node *parent = NULL;
+	struct ion_iommu_map *entry;
+	uint64_t key = domain_no;
+	key = key << 32 | partition_no;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct ion_iommu_map, node);
+
+		if (key < entry->key)
+			p = &(*p)->rb_left;
+		else if (key > entry->key)
+			p = &(*p)->rb_right;
+		else
+			return entry;
+	}
+
+	return NULL;
+}
+
+static int ion_iommu_map_iommu(struct ion_iommu_meta *meta,
+					struct ion_iommu_map *data,
+					unsigned int domain_num,
+					unsigned int partition_num,
+					unsigned long align,
+					unsigned long iova_length,
+					unsigned long flags)
+{
+	struct iommu_domain *domain;
+	int ret = 0;
+	unsigned long extra, size;
+	struct sg_table *table;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+
+
+	size = meta->size;
+	data->mapped_size = iova_length;
+	extra = iova_length - size;
+	table = meta->table;
+
+	/* Use the biggest alignment to allow bigger IOMMU mappings.
+	 * Use the first entry since the first entry will always be the
+	 * biggest entry. To take advantage of bigger mapping sizes both the
+	 * VA and PA addresses have to be aligned to the biggest size.
+	 */
+	if (table->sgl->length > align)
+		align = table->sgl->length;
+
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
+
+	if (ret)
+		goto out;
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	ret = iommu_map_range(domain, data->iova_addr,
+			      table->sgl,
+			      size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
+	}
+
+	if (extra) {
+		unsigned long extra_iova_addr = data->iova_addr + size;
+		unsigned long phys_addr = sg_phys(table->sgl);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
+					extra, SZ_4K, prot);
+		if (ret)
+			goto out2;
+	}
+	return ret;
+
+out2:
+	iommu_unmap_range(domain, data->iova_addr, size);
+out1:
+	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+				size);
+
+out:
+
+	return ret;
+}
+
+static void ion_iommu_heap_unmap_iommu(struct ion_iommu_map *data)
+{
+	unsigned int domain_num;
+	unsigned int partition_num;
+	struct iommu_domain *domain;
+
+	BUG_ON(!msm_use_iommu());
+
+	domain_num = iommu_map_domain(data);
+	partition_num = iommu_map_partition(data);
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+		return;
+	}
+
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
+	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+				data->mapped_size);
+
+	return;
+}
+
+
+
+static struct ion_iommu_map *__ion_iommu_map(struct ion_iommu_meta *meta,
+		int domain_num, int partition_num, unsigned long align,
+		unsigned long iova_length, unsigned long flags,
+		unsigned long *iova)
+{
+	struct ion_iommu_map *data;
+	int ret;
+
+	data = kmalloc(sizeof(*data), GFP_ATOMIC);
+
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	iommu_map_domain(data) = domain_num;
+	iommu_map_partition(data) = partition_num;
+
+	ret = ion_iommu_map_iommu(meta, data,
+						domain_num,
+						partition_num,
+						align,
+						iova_length,
+						flags);
+
+	if (ret)
+		goto out;
+
+	kref_init(&data->ref);
+	*iova = data->iova_addr;
+	data->meta = meta;
+
+	ion_iommu_add(meta, data);
+
+	return data;
+
+out:
+	kfree(data);
+	return ERR_PTR(ret);
+}
+
+static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_handle *handle,
+						struct sg_table *table,
+						unsigned long size)
+{
+	struct ion_iommu_meta *meta;
+
+	meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+
+	if (!meta)
+		return ERR_PTR(-ENOMEM);
+
+	meta->handle = handle;
+	meta->table = table;
+	meta->size = size;
+	kref_init(&meta->ref);
+	mutex_init(&meta->lock);
+	ion_iommu_meta_add(meta);
+
+	return meta;
+}
+
+static void ion_iommu_meta_destroy(struct kref *kref)
+{
+	struct ion_iommu_meta *meta = container_of(kref, struct ion_iommu_meta,
+						ref);
+
+
+	rb_erase(&meta->node, &iommu_root);
+	kfree(meta);
+}
+
+static void ion_iommu_meta_put(struct ion_iommu_meta *meta)
+{
+	/*
+	 * Need to lock here to prevent race against map/unmap
+	 */
+	mutex_lock(&msm_iommu_map_mutex);
+	kref_put(&meta->ref, ion_iommu_meta_destroy);
+	mutex_unlock(&msm_iommu_map_mutex);
+}
+
+int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
+			int domain_num, int partition_num, unsigned long align,
+			unsigned long iova_length, unsigned long *iova,
+			unsigned long *buffer_size,
+			unsigned long flags, unsigned long iommu_flags)
+{
+	struct ion_iommu_map *iommu_map;
+	struct ion_iommu_meta *iommu_meta = NULL;
+	struct sg_table *table;
+	struct scatterlist *sg;
+	int ret = 0;
+	int i;
+	unsigned long size = 0;
+
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("%s: client pointer is invalid\n", __func__);
+		return -EINVAL;
+	}
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: handle pointer is invalid\n", __func__);
+		return -EINVAL;
+	}
+
+	table = ion_sg_table(client, handle);
+
+	if (IS_ERR_OR_NULL(table))
+		return PTR_ERR(table);
+
+	for_each_sg(table->sgl, sg, table->nents, i)
+		size += sg_dma_len(sg);
+
+	if (!msm_use_iommu()) {
+		unsigned long pa = sg_dma_address(table->sgl);
+		if (pa == 0)
+			pa = sg_phys(table->sgl);
+		*iova = pa;
+		*buffer_size = size;
+	}
+	/*
+	 * If clients don't want a custom iova length, just use whatever
+	 * the buffer size is
+	 */
+	if (!iova_length)
+		iova_length = size;
+
+	if (size > iova_length) {
+		pr_debug("%s: iova length %lx is not at least buffer size %lx\n",
+			__func__, iova_length, size);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (size & ~PAGE_MASK) {
+		pr_debug("%s: buffer size %lx is not aligned to %lx", __func__,
+			size, PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (iova_length & ~PAGE_MASK) {
+		pr_debug("%s: iova_length %lx is not aligned to %lx", __func__,
+			iova_length, PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	mutex_lock(&msm_iommu_map_mutex);
+	iommu_meta = ion_iommu_meta_lookup(handle);
+
+	if (!iommu_meta)
+		iommu_meta = ion_iommu_meta_create(handle, table, size);
+	else
+		kref_get(&iommu_meta->ref);
+
+	mutex_unlock(&msm_iommu_map_mutex);
+
+	iommu_map = ion_iommu_lookup(iommu_meta, domain_num, partition_num);
+	if (!iommu_map) {
+		iommu_map = __ion_iommu_map(iommu_meta, domain_num,
+					    partition_num, align, iova_length,
+					    flags, iova);
+		if (!IS_ERR_OR_NULL(iommu_map)) {
+			iommu_map->flags = iommu_flags;
+			ret = 0;
+		} else {
+			ret = PTR_ERR(iommu_map);
+			goto out;
+		}
+	} else {
+		if (iommu_map->flags != iommu_flags) {
+			pr_err("%s: handle %p is already mapped with iommu flags %lx, trying to map with flags %lx\n",
+				__func__, handle,
+				iommu_map->flags, iommu_flags);
+			ret = -EINVAL;
+			goto out;
+		} else if (iommu_map->mapped_size != iova_length) {
+			pr_err("%s: handle %p is already mapped with length %x, trying to map with length %lx\n",
+				__func__, handle, iommu_map->mapped_size,
+				iova_length);
+			ret = -EINVAL;
+			goto out;
+		} else {
+			kref_get(&iommu_map->ref);
+			*iova = iommu_map->iova_addr;
+		}
+	}
+	*buffer_size = size;
+	return ret;
+
+out:
+
+	ion_iommu_meta_put(iommu_meta);
+	return ret;
+}
+EXPORT_SYMBOL(ion_map_iommu);
+
+
+static void ion_iommu_map_release(struct kref *kref)
+{
+	struct ion_iommu_map *map = container_of(kref, struct ion_iommu_map,
+						ref);
+	struct ion_iommu_meta *meta = map->meta;
+
+	rb_erase(&map->node, &meta->iommu_maps);
+	ion_iommu_heap_unmap_iommu(map);
+	kfree(map);
+}
+
+void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle,
+			int domain_num, int partition_num)
+{
+	struct ion_iommu_map *iommu_map;
+	struct ion_iommu_meta *meta;
+
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("%s: client pointer is invalid\n", __func__);
+		return;
+	}
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: handle pointer is invalid\n", __func__);
+		return;
+	}
+
+
+	mutex_lock(&msm_iommu_map_mutex);
+	meta = ion_iommu_meta_lookup(handle);
+	if (!meta) {
+		WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
+				domain_num, partition_num, handle);
+		mutex_lock(&msm_iommu_map_mutex);
+		goto out;
+
+	}
+	mutex_unlock(&msm_iommu_map_mutex);
+
+	mutex_lock(&meta->lock);
+	iommu_map = ion_iommu_lookup(meta, domain_num, partition_num);
+
+	if (!iommu_map) {
+		WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
+				domain_num, partition_num, handle);
+		mutex_unlock(&meta->lock);
+		goto out;
+	}
+
+	kref_put(&iommu_map->ref, ion_iommu_map_release);
+	mutex_unlock(&meta->lock);
+
+	ion_iommu_meta_put(meta);
+
+out:
+	return;
+}
+EXPORT_SYMBOL(ion_unmap_iommu);
+
+
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 4b55875..9259de2 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -26,8 +26,10 @@
 #include <linux/rwsem.h>
 #include <linux/uaccess.h>
 #include <linux/memblock.h>
+#include <linux/dma-mapping.h>
 #include <mach/ion.h>
 #include <mach/msm_memtypes.h>
+#include <asm/cacheflush.h>
 #include "../ion_priv.h"
 #include "ion_cp_common.h"
 
@@ -177,6 +179,210 @@
 }
 EXPORT_SYMBOL(msm_ion_do_cache_op);
 
+static int ion_no_pages_cache_ops(struct ion_client *client,
+			struct ion_handle *handle,
+			void *vaddr,
+			unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t) = NULL;
+	unsigned int size_to_vmap, total_size;
+	int i, j, ret;
+	void *ptr = NULL;
+	ion_phys_addr_t buff_phys = 0;
+	ion_phys_addr_t buff_phys_start = 0;
+	size_t buf_length = 0;
+
+	ret = ion_phys(client, handle, &buff_phys_start, &buf_length);
+	if (ret)
+		return -EINVAL;
+
+	buff_phys = buff_phys_start;
+
+	if (!vaddr) {
+		/*
+		 * Split the vmalloc space into smaller regions in
+		 * order to clean and/or invalidate the cache.
+		 */
+		size_to_vmap = ((VMALLOC_END - VMALLOC_START)/8);
+		total_size = buf_length;
+
+		for (i = 0; i < total_size; i += size_to_vmap) {
+			size_to_vmap = min(size_to_vmap, total_size - i);
+			for (j = 0; j < 10 && size_to_vmap; ++j) {
+				ptr = ioremap(buff_phys, size_to_vmap);
+				if (ptr) {
+					switch (cmd) {
+					case ION_IOC_CLEAN_CACHES:
+						dmac_clean_range(ptr,
+							ptr + size_to_vmap);
+						outer_cache_op =
+							outer_clean_range;
+						break;
+					case ION_IOC_INV_CACHES:
+						dmac_inv_range(ptr,
+							ptr + size_to_vmap);
+						outer_cache_op =
+							outer_inv_range;
+						break;
+					case ION_IOC_CLEAN_INV_CACHES:
+						dmac_flush_range(ptr,
+							ptr + size_to_vmap);
+						outer_cache_op =
+							outer_flush_range;
+						break;
+					default:
+						return -EINVAL;
+					}
+					buff_phys += size_to_vmap;
+					break;
+				} else {
+					size_to_vmap >>= 1;
+				}
+			}
+			if (!ptr) {
+				pr_err("Couldn't io-remap the memory\n");
+				return -EINVAL;
+			}
+			iounmap(ptr);
+		}
+	} else {
+		switch (cmd) {
+		case ION_IOC_CLEAN_CACHES:
+			dmac_clean_range(vaddr, vaddr + length);
+			outer_cache_op = outer_clean_range;
+			break;
+		case ION_IOC_INV_CACHES:
+			dmac_inv_range(vaddr, vaddr + length);
+			outer_cache_op = outer_inv_range;
+			break;
+		case ION_IOC_CLEAN_INV_CACHES:
+			dmac_flush_range(vaddr, vaddr + length);
+			outer_cache_op = outer_flush_range;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	outer_cache_op(buff_phys_start + offset,
+		       buff_phys_start + offset + length);
+
+	return 0;
+}
+
+#ifdef CONFIG_OUTER_CACHE
+static void ion_pages_outer_cache_op(void (*op)(phys_addr_t, phys_addr_t),
+				struct sg_table *table)
+{
+	unsigned long pstart;
+	struct scatterlist *sg;
+	int i;
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		struct page *page = sg_page(sg);
+		pstart = page_to_phys(page);
+		/*
+		 * If page -> phys is returning NULL, something
+		 * has really gone wrong...
+		 */
+		if (!pstart) {
+			WARN(1, "Could not translate virtual address to physical address\n");
+			return;
+		}
+		op(pstart, pstart + PAGE_SIZE);
+	}
+}
+#else
+static void ion_pages_outer_cache_op(void (*op)(phys_addr_t, phys_addr_t),
+					struct sg_table *table)
+{
+
+}
+#endif
+
+static int ion_pages_cache_ops(struct ion_client *client,
+			struct ion_handle *handle,
+			void *vaddr, unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+	struct sg_table *table = NULL;
+
+	table = ion_sg_table(client, handle);
+	if (IS_ERR_OR_NULL(table))
+		return PTR_ERR(table);
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		if (!vaddr)
+			dma_sync_sg_for_device(NULL, table->sgl,
+				table->nents, DMA_TO_DEVICE);
+		else
+			dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
+		break;
+	case ION_IOC_INV_CACHES:
+		if (!vaddr)
+			dma_sync_sg_for_cpu(NULL, table->sgl,
+				table->nents, DMA_FROM_DEVICE);
+		else
+			dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		if (!vaddr) {
+			dma_sync_sg_for_device(NULL, table->sgl,
+				table->nents, DMA_TO_DEVICE);
+			dma_sync_sg_for_cpu(NULL, table->sgl,
+				table->nents, DMA_FROM_DEVICE);
+		} else {
+			dmac_flush_range(vaddr, vaddr + length);
+		}
+		outer_cache_op = outer_flush_range;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ion_pages_outer_cache_op(outer_cache_op, table);
+
+	return 0;
+}
+
+int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+			void *uaddr, unsigned long offset, unsigned long len,
+			unsigned int cmd)
+{
+	int ret = -EINVAL;
+	unsigned long flags;
+	struct sg_table *table;
+	struct page *page;
+
+	ret = ion_handle_get_flags(client, handle, &flags);
+	if (ret)
+		return -EINVAL;
+
+	if (!ION_IS_CACHED(flags))
+		return 0;
+
+	table = ion_sg_table(client, handle);
+
+	if (IS_ERR_OR_NULL(table))
+		return PTR_ERR(table);
+
+	page = sg_page(table->sgl);
+
+	if (page)
+		ret = ion_pages_cache_ops(client, handle, uaddr,
+					offset, len, cmd);
+	else
+		ret = ion_no_pages_cache_ops(client, handle, uaddr,
+					offset, len, cmd);
+
+	return ret;
+
+}
+
 static ion_phys_addr_t msm_ion_get_base(unsigned long size, int memory_type,
 				    unsigned int align)
 {
@@ -770,6 +976,10 @@
 		heap = ion_secure_cma_heap_create(heap_data);
 		break;
 #endif
+	case ION_HEAP_TYPE_REMOVED:
+		heap = ion_removed_heap_create(heap_data);
+		break;
+
 	default:
 		heap = ion_heap_create(heap_data);
 	}
@@ -807,6 +1017,9 @@
 		ion_secure_cma_heap_destroy(heap);
 		break;
 #endif
+	case ION_HEAP_TYPE_REMOVED:
+		ion_removed_heap_destroy(heap);
+		break;
 	default:
 		ion_heap_destroy(heap);
 	}
diff --git a/drivers/gpu/ion/msm_ion_priv.h b/drivers/gpu/ion/msm_ion_priv.h
index 44f434a..2de4e8a 100644
--- a/drivers/gpu/ion/msm_ion_priv.h
+++ b/drivers/gpu/ion/msm_ion_priv.h
@@ -26,42 +26,6 @@
 #include <linux/iommu.h>
 #include <linux/seq_file.h>
 
-enum {
-	DI_PARTITION_NUM = 0,
-	DI_DOMAIN_NUM = 1,
-	DI_MAX,
-};
-
-/**
- * struct ion_iommu_map - represents a mapping of an ion buffer to an iommu
- * @iova_addr - iommu virtual address
- * @node - rb node to exist in the buffer's tree of iommu mappings
- * @domain_info - contains the partition number and domain number
- *		domain_info[1] = domain number
- *		domain_info[0] = partition number
- * @ref - for reference counting this mapping
- * @mapped_size - size of the iova space mapped
- *		(may not be the same as the buffer size)
- * @flags - iommu domain/partition specific flags.
- *
- * Represents a mapping of one ion buffer to a particular iommu domain
- * and address range. There may exist other mappings of this buffer in
- * different domains or address ranges. All mappings will have the same
- * cacheability and security.
- */
-struct ion_iommu_map {
-	unsigned long iova_addr;
-	struct rb_node node;
-	union {
-		int domain_info[DI_MAX];
-		uint64_t key;
-	};
-	struct ion_buffer *buffer;
-	struct kref ref;
-	int mapped_size;
-	unsigned long flags;
-};
-
 /**
  * struct mem_map_data - represents information about the memory map for a heap
  * @node:		rb node used to store in the tree of mem_map_data
@@ -79,9 +43,6 @@
 	const char *client_name;
 };
 
-#define iommu_map_domain(__m)		((__m)->domain_info[1])
-#define iommu_map_partition(__m)	((__m)->domain_info[0])
-
 struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *);
 void ion_iommu_heap_destroy(struct ion_heap *);
 
@@ -96,6 +57,9 @@
 void ion_secure_cma_heap_destroy(struct ion_heap *);
 #endif
 
+struct ion_heap *ion_removed_heap_create(struct ion_platform_heap *);
+void ion_removed_heap_destroy(struct ion_heap *);
+
 #define ION_CP_ALLOCATE_FAIL -1
 #define ION_RESERVED_ALLOCATE_FAIL -1
 
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index a2f0e60..c768bb7 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -396,6 +396,19 @@
 #define A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x3058
 #define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
 #define A3XX_VBIF_OUT_AXI_AOOO 0x305F
+#define A3XX_VBIF_PERF_CNT_EN 0x3070
+#define A3XX_VBIF_PERF_CNT_CLR 0x3071
+#define A3XX_VBIF_PERF_CNT_SEL 0x3072
+#define A3XX_VBIF_PERF_CNT0_LO 0x3073
+#define A3XX_VBIF_PERF_CNT0_HI 0x3074
+#define A3XX_VBIF_PERF_CNT1_LO 0x3075
+#define A3XX_VBIF_PERF_CNT1_HI 0x3076
+#define A3XX_VBIF_PERF_PWR_CNT0_LO 0x3077
+#define A3XX_VBIF_PERF_PWR_CNT0_HI 0x3078
+#define A3XX_VBIF_PERF_PWR_CNT1_LO 0x3079
+#define A3XX_VBIF_PERF_PWR_CNT1_HI 0x307a
+#define A3XX_VBIF_PERF_PWR_CNT2_LO 0x307b
+#define A3XX_VBIF_PERF_PWR_CNT2_HI 0x307c
 
 /* Bit flags for RBBM_CTL */
 #define RBBM_RBBM_CTL_RESET_PWR_CTR0  BIT(0)
@@ -670,11 +683,11 @@
 #define A305C_RBBM_CLOCK_CTL_DEFAULT  0xAAAAAAAA
 #define A320_RBBM_CLOCK_CTL_DEFAULT   0xBFFFFFFF
 #define A330_RBBM_CLOCK_CTL_DEFAULT   0xBFFCFFFF
-#define A330v2_RBBM_CLOCK_CTL_DEFAULT 0xBFFCFFFF
+#define A330v2_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA
 #define A305B_RBBM_CLOCK_CTL_DEFAULT  0xAAAAAAAA
 
 #define A330_RBBM_GPR0_CTL_DEFAULT    0x00000000
-#define A330v2_RBBM_GPR0_CTL_DEFAULT  0x00000000
+#define A330v2_RBBM_GPR0_CTL_DEFAULT  0x05515455
 
 /* COUNTABLE FOR SP PERFCOUNTER */
 #define SP_FS_FULL_ALU_INSTRUCTIONS    0x0E
@@ -682,4 +695,20 @@
 #define SP0_ICL1_MISSES                0x1A
 #define SP_FS_CFLOW_INSTRUCTIONS       0x0C
 
+/* VBIF PERFCOUNTER ENA/CLR values */
+#define VBIF_PERF_CNT_0 BIT(0)
+#define VBIF_PERF_CNT_1 BIT(1)
+#define VBIF_PERF_PWR_CNT_0 BIT(2)
+#define VBIF_PERF_PWR_CNT_1 BIT(3)
+#define VBIF_PERF_PWR_CNT_2 BIT(4)
+
+/* VBIF PERFCOUNTER SEL values */
+#define VBIF_PERF_CNT_0_SEL 0
+#define VBIF_PERF_CNT_0_SEL_MASK 0x7f
+#define VBIF_PERF_CNT_1_SEL 8
+#define VBIF_PERF_CNT_1_SEL_MASK 0x7f00
+
+/* VBIF countables */
+#define VBIF_DDR_TOTAL_CYCLES 110
+
 #endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 62b6a71..5589ff0 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1859,7 +1859,8 @@
 	}
 	if (status)
 		KGSL_FT_ERR(rb->device,
-		"Failed to find the command sequence after eop timestamp\n");
+		"Failed to find the command sequence after eop timestamp %x\n",
+		global_eop);
 	return status;
 }
 
@@ -1972,44 +1973,38 @@
 
 	/* find the start of bad command sequence in rb */
 	context = idr_find(&device->context_idr, ft_data->context_id);
-	/* Look for the command stream that is right after the global eop */
-
-	if (!context) {
-		/*
-		 * If there is no context then fault tolerance does not need to
-		 * replay anything, just reset GPU and thats it
-		 */
-		return;
-	}
 
 	ft_data->ft_policy = adreno_dev->ft_policy;
 
 	if (!ft_data->ft_policy)
 		ft_data->ft_policy = KGSL_FT_DEFAULT_POLICY;
 
+	/* Look for the command stream that is right after the global eop */
 	ret = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
 					ft_data->global_eop + 1, false);
 	if (ret) {
 		ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE;
 		return;
-	} else
+	} else {
+		ft_data->start_of_replay_cmds = rb_rptr;
 		ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE;
+	}
 
-	ft_data->start_of_replay_cmds = rb_rptr;
-
-	adreno_context = context->devctxt;
-	if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
-		if (ft_data->ib1) {
-			ret = _find_hanging_ib_sequence(rb,
-					&rb_rptr, ft_data->ib1);
-			if (ret) {
-				KGSL_FT_ERR(device,
-				"Start not found for replay IB sequence\n");
-				ret = 0;
-				return;
+	if (context) {
+		adreno_context = context->devctxt;
+		if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
+			if (ft_data->ib1) {
+				ret = _find_hanging_ib_sequence(rb,
+						&rb_rptr, ft_data->ib1);
+				if (ret) {
+					KGSL_FT_ERR(device,
+					"Start not found for replay IB seq\n");
+					ret = 0;
+					return;
+				}
+				ft_data->start_of_replay_cmds = rb_rptr;
+				ft_data->replay_for_snapshot = rb_rptr;
 			}
-			ft_data->start_of_replay_cmds = rb_rptr;
-			ft_data->replay_for_snapshot = rb_rptr;
 		}
 	}
 }
@@ -2046,9 +2041,6 @@
 _adreno_ft_restart_device(struct kgsl_device *device,
 			   struct kgsl_context *context)
 {
-
-	struct adreno_context *adreno_context = context->devctxt;
-
 	/* restart device */
 	if (adreno_stop(device)) {
 		KGSL_FT_ERR(device, "Device stop failed\n");
@@ -2065,9 +2057,11 @@
 		return 1;
 	}
 
-	if (context)
+	if (context) {
+		struct adreno_context *adreno_context = context->devctxt;
 		kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
 			KGSL_MEMSTORE_GLOBAL);
+	}
 
 	/* If iommu is used then we need to make sure that the iommu clocks
 	 * are on since there could be commands in pipeline that touch iommu */
@@ -2168,13 +2162,22 @@
 	struct adreno_context *adreno_context = NULL;
 	struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
 	unsigned int long_ib = 0;
+	static int no_context_ft;
 
 	context = idr_find(&device->context_idr, ft_data->context_id);
 	if (context == NULL) {
 		KGSL_FT_ERR(device, "Last context unknown id:%d\n",
 			ft_data->context_id);
-		goto play_good_cmds;
+		if (no_context_ft) {
+			/*
+			 * If 2 consecutive no context ft occurred then
+			 * just reset GPU
+			 */
+			no_context_ft = 0;
+			goto play_good_cmds;
+		}
 	} else {
+		no_context_ft = 0;
 		adreno_context = context->devctxt;
 		adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
 		/*
@@ -2230,7 +2233,7 @@
 	}
 
 	/* Do not try the reply if hang is due to a pagefault */
-	if (adreno_context->pagefault) {
+	if (adreno_context && adreno_context->pagefault) {
 		if ((ft_data->context_id == adreno_context->id) &&
 			(ft_data->global_eop == adreno_context->pagefault_ts)) {
 			ft_data->ft_policy &= ~KGSL_FT_REPLAY;
@@ -2295,7 +2298,7 @@
 
 		/* EOF not found in RB, discard till EOF in
 		   next IB submission */
-		if (i == ft_data->bad_rb_size) {
+		if (adreno_context && (i == ft_data->bad_rb_size)) {
 			adreno_context->flags |= CTXT_FLAGS_SKIP_EOF;
 			KGSL_FT_INFO(device,
 			"EOF not found in RB, skip next issueib till EOF\n");
@@ -2332,8 +2335,14 @@
 			ft_data->good_rb_buffer, ft_data->good_rb_size);
 
 	if (ret) {
-		/* If we fail here we can try to invalidate another
-		 * context and try fault tolerance again */
+		/*
+		 * If we fail here we can try to invalidate another
+		 * context and try fault tolerance again, although
+		 * we will only try ft with no context once to avoid
+		 * going into continuous loop of trying ft with no context
+		 */
+		if (!context)
+			no_context_ft = 1;
 		ret = -EAGAIN;
 		KGSL_FT_ERR(device, "Playing good commands unsuccessful\n");
 		goto done;
@@ -3166,6 +3175,31 @@
 					"Fault tolerance no context found\n");
 			}
 		}
+		for (i = 0; i < ft_detect_regs_count; i++) {
+			if (curr_reg_val[i] != prev_reg_val[i]) {
+				fast_hang_detected = 0;
+
+				/* Check for long IB here */
+				if ((i >=
+					LONG_IB_DETECT_REG_INDEX_START)
+					&&
+					(i <=
+					LONG_IB_DETECT_REG_INDEX_END))
+					long_ib_detected = 0;
+			}
+		}
+
+		if (fast_hang_detected) {
+			KGSL_FT_ERR(device,
+				"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
+				" on global ts %d\n",
+				curr_context ? curr_context->pid_name : "",
+				curr_context ? curr_context->id : 0,
+				(kgsl_readtimestamp(device, context,
+				KGSL_TIMESTAMP_RETIRED) + 1),
+				curr_global_ts + 1);
+			return 1;
+		}
 
 		if (curr_context != NULL) {
 
@@ -3175,31 +3209,6 @@
 			curr_context->pid_name, curr_context->ib_gpu_time_used,
 			curr_global_ts+1);
 
-			for (i = 0; i < ft_detect_regs_count; i++) {
-				if (curr_reg_val[i] != prev_reg_val[i]) {
-					fast_hang_detected = 0;
-
-					/* Check for long IB here */
-					if ((i >=
-						LONG_IB_DETECT_REG_INDEX_START)
-						&&
-						(i <=
-						LONG_IB_DETECT_REG_INDEX_END))
-						long_ib_detected = 0;
-				}
-			}
-
-			if (fast_hang_detected) {
-				KGSL_FT_ERR(device,
-					"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
-					" on global ts %d\n",
-					curr_context->pid_name, curr_context->id
-					, (kgsl_readtimestamp(device, context,
-					KGSL_TIMESTAMP_RETIRED)+1),
-					curr_global_ts+1);
-				return 1;
-			}
-
 			if ((long_ib_detected) &&
 				(!(curr_context->flags &
 				 CTXT_FLAGS_NO_FAULT_TOLERANCE))) {
@@ -3229,10 +3238,6 @@
 					}
 				}
 			}
-		} else {
-			KGSL_FT_ERR(device,
-				"Last context unknown id:%d\n",
-				curr_context_id);
 		}
 	} else {
 		/* GPU is moving forward */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 13c723a..be5c786 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2752,6 +2752,58 @@
 	return;
 }
 
+static void a3xx_perfcounter_enable_vbif(struct kgsl_device *device,
+					 unsigned int counter,
+					 unsigned int countable)
+{
+	unsigned int in, out, bit, sel;
+
+	if (countable > 0x7f)
+		return;
+
+	adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
+	adreno_regread(device, A3XX_VBIF_PERF_CNT_SEL, &sel);
+
+	if (counter == 0) {
+		bit = VBIF_PERF_CNT_0;
+		sel = (sel & ~VBIF_PERF_CNT_0_SEL_MASK) | countable;
+	} else if (counter == 1) {
+		bit = VBIF_PERF_CNT_1;
+		sel = (sel & ~VBIF_PERF_CNT_1_SEL_MASK)
+			| (countable << VBIF_PERF_CNT_1_SEL);
+	}
+
+	out = in | bit;
+
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_SEL, sel);
+
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit);
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0);
+
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out);
+}
+
+static void a3xx_perfcounter_enable_vbif_pwr(struct kgsl_device *device,
+					     unsigned int countable)
+{
+	unsigned int in, out, bit;
+
+	adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in);
+	if (countable == 0)
+		bit = VBIF_PERF_PWR_CNT_0;
+	else if (countable == 1)
+		bit = VBIF_PERF_PWR_CNT_1;
+	else
+		bit = VBIF_PERF_PWR_CNT_2;
+
+	out = in | bit;
+
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit);
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0);
+
+	adreno_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out);
+}
+
 /*
  * a3xx_perfcounter_enable - Configure a performance counter for a countable
  * @adreno_dev -  Adreno device to configure
@@ -2775,9 +2827,13 @@
 	if (counter > a3xx_perfcounter_reglist[group].count)
 		return;
 
-	/* Special case - power */
+	/* Special cases */
 	if (group == KGSL_PERFCOUNTER_GROUP_PWR)
 		return a3xx_perfcounter_enable_pwr(device, countable);
+	else if (group == KGSL_PERFCOUNTER_GROUP_VBIF)
+		return a3xx_perfcounter_enable_vbif(device, counter, countable);
+	else if (group == KGSL_PERFCOUNTER_GROUP_VBIF_PWR)
+		return a3xx_perfcounter_enable_vbif_pwr(device, countable);
 
 	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
 
@@ -3265,6 +3321,16 @@
 	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_1_LO, 0 },
 };
 
+static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_CNT0_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_CNT1_LO },
+};
+static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT0_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT2_LO },
+};
+
 static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
 	{ a3xx_perfcounters_cp, ARRAY_SIZE(a3xx_perfcounters_cp) },
 	{ a3xx_perfcounters_rbbm, ARRAY_SIZE(a3xx_perfcounters_rbbm) },
@@ -3279,6 +3345,8 @@
 	{ a3xx_perfcounters_sp, ARRAY_SIZE(a3xx_perfcounters_sp) },
 	{ a3xx_perfcounters_rb, ARRAY_SIZE(a3xx_perfcounters_rb) },
 	{ a3xx_perfcounters_pwr, ARRAY_SIZE(a3xx_perfcounters_pwr) },
+	{ a3xx_perfcounters_vbif, ARRAY_SIZE(a3xx_perfcounters_vbif) },
+	{ a3xx_perfcounters_vbif_pwr, ARRAY_SIZE(a3xx_perfcounters_vbif_pwr) },
 };
 
 static struct adreno_perfcounters a3xx_perfcounters = {
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index aea3431..f0b9b05 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -74,7 +74,8 @@
 	DMX_FRAME_ERROR, /* Frame alignment error */
 	DMX_FIFO_ERROR, /* Receiver FIFO overrun */
 	DMX_MISSED_ERROR, /* Receiver missed packet */
-	DMX_OK_DECODER_BUF /* Received OK, new ES data in decoder buffer */
+	DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */
+	DMX_OK_IDX /* Received OK, new index event */
 } ;
 
 
@@ -131,6 +132,8 @@
 		struct {
 			u64 id;
 		} marker;
+
+		struct dmx_index_event_info idx_event;
 	};
 };
 
@@ -222,8 +225,10 @@
 		    struct timespec timeout);
 	int (*start_filtering) (struct dmx_ts_feed* feed);
 	int (*stop_filtering) (struct dmx_ts_feed* feed);
-	int (*set_indexing_params) (struct dmx_ts_feed *feed,
-				struct dmx_indexing_video_params *params);
+	int (*set_video_codec) (struct dmx_ts_feed *feed,
+				enum dmx_video_codec video_codec);
+	int (*set_idx_params) (struct dmx_ts_feed *feed,
+				struct dmx_indexing_params *idx_params);
 	int (*get_decoder_buff_status)(
 			struct dmx_ts_feed *feed,
 			struct dmx_buffer_status *dmx_buffer_status);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 219970b..ca71c06 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1714,8 +1714,44 @@
 	return 0;
 }
 
-static int dvb_dmxdev_ts_fullness_callback(
-				struct dmx_ts_feed *filter,
+static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter,
+				struct dmx_indexing_params *idx_params)
+{
+	int found_pid;
+	struct dmxdev_feed *feed;
+	struct dmxdev_feed *ts_feed = NULL;
+
+	if (!idx_params ||
+		(dmxdevfilter->state < DMXDEV_STATE_SET) ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+		 (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+		return -EINVAL;
+
+	if (idx_params->enable && !idx_params->types)
+		return -EINVAL;
+
+	found_pid = 0;
+	list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+		if (feed->pid == idx_params->pid) {
+			found_pid = 1;
+			ts_feed = feed;
+			ts_feed->idx_params = *idx_params;
+			if ((dmxdevfilter->state == DMXDEV_STATE_GO) &&
+				ts_feed->ts->set_idx_params)
+				ts_feed->ts->set_idx_params(
+						ts_feed->ts, idx_params);
+			break;
+		}
+	}
+
+	if (!found_pid)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
 				int required_space)
 {
 	struct dmxdev_filter *dmxdevfilter = filter->priv;
@@ -2349,6 +2385,17 @@
 		return 0;
 	}
 
+	if (dmx_data_ready->status == DMX_OK_IDX) {
+		dprintk("dmxdev: event callback DMX_OK_IDX\n");
+		event.type = DMX_EVENT_NEW_INDEX_ENTRY;
+		event.params.index = dmx_data_ready->idx_event;
+
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
 	if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
 		event.type = DMX_EVENT_NEW_ES_DATA;
 		event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
@@ -2706,15 +2753,13 @@
 	if (tsfeed->set_secure_mode)
 		tsfeed->set_secure_mode(tsfeed, &feed->sec_mode);
 
-	/* Support indexing for video PES */
 	if ((para->pes_type == DMX_PES_VIDEO0) ||
 	    (para->pes_type == DMX_PES_VIDEO1) ||
 	    (para->pes_type == DMX_PES_VIDEO2) ||
 	    (para->pes_type == DMX_PES_VIDEO3)) {
-
-		if (tsfeed->set_indexing_params) {
-			ret = tsfeed->set_indexing_params(tsfeed,
-							&para->video_params);
+		if (tsfeed->set_video_codec) {
+			ret = tsfeed->set_video_codec(tsfeed,
+							para->video_codec);
 
 			if (ret < 0) {
 				dmxdev->demux->release_ts_feed(dmxdev->demux,
@@ -2724,6 +2769,12 @@
 		}
 	}
 
+	if ((filter->params.pes.output == DMX_OUT_TS_TAP) ||
+		(filter->params.pes.output == DMX_OUT_TSDEMUX_TAP))
+		if (tsfeed->set_idx_params)
+			tsfeed->set_idx_params(
+					tsfeed, &feed->idx_params);
+
 	ret = tsfeed->start_filtering(tsfeed);
 	if (ret < 0) {
 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
@@ -3034,6 +3085,7 @@
 
 	feed->pid = pid;
 	feed->sec_mode.is_secured = 0;
+	feed->idx_params.enable = 0;
 	list_add(&feed->next, &filter->feed.ts);
 
 	if (filter->state >= DMXDEV_STATE_GO)
@@ -3158,23 +3210,6 @@
 	if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
 		return -EINVAL;
 
-	if (params->flags & DMX_ENABLE_INDEXING) {
-		if (!(dmxdev->capabilities & DMXDEV_CAP_INDEXING))
-			return -EINVAL;
-
-		/* can do indexing only on video PES */
-		if ((params->pes_type != DMX_PES_VIDEO0) &&
-		    (params->pes_type != DMX_PES_VIDEO1) &&
-		    (params->pes_type != DMX_PES_VIDEO2) &&
-		    (params->pes_type != DMX_PES_VIDEO3))
-			return -EINVAL;
-
-		/* can do indexing only when recording */
-		if ((params->output != DMX_OUT_TS_TAP) &&
-		    (params->output != DMX_OUT_TSDEMUX_TAP))
-			return -EINVAL;
-	}
-
 	dmxdevfilter->type = DMXDEV_TYPE_PES;
 	memcpy(&dmxdevfilter->params, params,
 	       sizeof(struct dmx_pes_filter_params));
@@ -3580,6 +3615,15 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_SET_INDEXING_PARAMS:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_indexing_params(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 7845b75..2ed99ae 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -59,6 +59,7 @@
 struct dmxdev_feed {
 	u16 pid;
 	struct dmx_secure_mode sec_mode;
+	struct dmx_indexing_params idx_params;
 	struct dmx_ts_feed *ts;
 	struct list_head next;
 };
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 3f73c4d..3f3d222 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -65,6 +65,91 @@
 			printk(x);                              \
 	} while (0)
 
+static const struct dvb_dmx_video_patterns mpeg2_seq_hdr = {
+	{0x00, 0x00, 0x01, 0xB3},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_MPEG_SEQ_HEADER
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_gop = {
+	{0x00, 0x00, 0x01, 0xB8},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_MPEG_GOP
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_iframe = {
+	{0x00, 0x00, 0x01, 0x00, 0x00, 0x08},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38},
+	6,
+	DMX_IDX_MPEG_I_FRAME_START
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_pframe = {
+	{0x00, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38},
+	6,
+	DMX_IDX_MPEG_P_FRAME_START
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_bframe = {
+	{0x00, 0x00, 0x01, 0x00, 0x00, 0x18},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38},
+	6,
+	DMX_IDX_MPEG_B_FRAME_START
+};
+
+static const struct dvb_dmx_video_patterns h264_sps = {
+	{0x00, 0x00, 0x01, 0x07},
+	{0xFF, 0xFF, 0xFF, 0x1F},
+	4,
+	DMX_IDX_H264_SPS
+};
+
+static const struct dvb_dmx_video_patterns h264_pps = {
+	{0x00, 0x00, 0x01, 0x08},
+	{0xFF, 0xFF, 0xFF, 0x1F},
+	4,
+	DMX_IDX_H264_PPS
+};
+
+static const struct dvb_dmx_video_patterns h264_idr = {
+	{0x00, 0x00, 0x01, 0x05, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x1F, 0x80},
+	5,
+	DMX_IDX_H264_IDR_START
+};
+
+static const struct dvb_dmx_video_patterns h264_non_idr = {
+	{0x00, 0x00, 0x01, 0x01, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x1F, 0x80},
+	5,
+	DMX_IDX_H264_NON_IDR_START
+};
+
+static const struct dvb_dmx_video_patterns vc1_seq_hdr = {
+	{0x00, 0x00, 0x01, 0x0F},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_VC1_SEQ_HEADER
+};
+
+static const struct dvb_dmx_video_patterns vc1_entry_point = {
+	{0x00, 0x00, 0x01, 0x0E},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_VC1_ENTRY_POINT
+};
+
+static const struct dvb_dmx_video_patterns vc1_frame = {
+	{0x00, 0x00, 0x01, 0x0D},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_VC1_FRAME_START
+};
+
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -122,6 +207,236 @@
  * Software filter functions
  ******************************************************************************/
 
+/*
+ * Check if two patterns are identical, taking mask into consideration.
+ * @pattern1: the first byte pattern to compare.
+ * @pattern2: the second byte pattern to compare.
+ * @mask: the bit mask to use.
+ * @pattern_size: the length of both patterns and the mask, in bytes.
+ *
+ * Return: 1 if patterns match, 0 otherwise.
+ */
+static inline int dvb_dmx_patterns_match(const u8 *pattern1, const u8 *pattern2,
+					const u8 *mask, size_t pattern_size)
+{
+	int i;
+
+	/*
+	 * Assumption: it is OK to access pattern1, pattern2 and mask.
+	 * This function performs no sanity checks to keep things fast.
+	 */
+
+	for (i = 0; i < pattern_size; i++)
+		if ((pattern1[i] & mask[i]) != (pattern2[i] & mask[i]))
+			return 0;
+
+	return 1;
+}
+
+/*
+ * dvb_dmx_video_pattern_search -
+ * search for framing patterns in a given buffer.
+ *
+ * Optimized version: first search for a common substring, e.g. 0x00 0x00 0x01.
+ * If this string is found, go over all the given patterns (all must start
+ * with this string) and search for their ending in the buffer.
+ *
+ * Assumption: the patterns we look for do not spread over more than two
+ * buffers.
+ *
+ * @paterns: the full patterns information to look for.
+ * @patterns_num: the number of patterns to look for.
+ * @buf: the buffer to search.
+ * @buf_size: the size of the buffer to search. we search the entire buffer.
+ * @prefix_size_masks: a bit mask (per pattern) of possible prefix sizes to use
+ * when searching for a pattern that started at the last buffer.
+ * Updated in this function for use in the next lookup.
+ * @results: lookup results (offset, type, used_prefix_size) per found pattern,
+ * up to DVB_DMX_MAX_FOUND_PATTERNS.
+ *
+ * Return:
+ *   Number of patterns found (up to DVB_DMX_MAX_FOUND_PATTERNS).
+ *   0 if pattern was not found.
+ *   error value on failure.
+ */
+int dvb_dmx_video_pattern_search(
+		const struct dvb_dmx_video_patterns
+			*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM],
+		int patterns_num,
+		const u8 *buf,
+		size_t buf_size,
+		struct dvb_dmx_video_prefix_size_masks *prefix_size_masks,
+		struct dvb_dmx_video_patterns_results *results)
+{
+	int i, j;
+	unsigned int current_size;
+	u32 prefix;
+	int found = 0;
+	int start_offset = 0;
+	/* the starting common substring to look for */
+	u8 string[] = {0x00, 0x00, 0x01};
+	/* the mask for the starting string */
+	u8 string_mask[] = {0xFF, 0xFF, 0xFF};
+	/* the size of the starting string (in bytes) */
+	size_t string_size = 3;
+
+	if ((patterns == NULL) || (patterns_num <= 0) || (buf == NULL))
+		return -EINVAL;
+
+	memset(results, 0, sizeof(struct dvb_dmx_video_patterns_results));
+
+	/*
+	 * handle prefix - disregard string, simply check all patterns,
+	 * looking for a matching suffix at the very beginning of the buffer.
+	 */
+	for (j = 0; (j < patterns_num) && !found; j++) {
+		prefix = prefix_size_masks->size_mask[j];
+		current_size = 32;
+		while (prefix) {
+			if (prefix & (0x1 << (current_size - 1))) {
+				/*
+				 * check that we don't look further
+				 * than buf_size boundary
+				 */
+				if ((int)(patterns[j]->size - current_size) >
+						buf_size)
+					break;
+
+				if (dvb_dmx_patterns_match(
+					(patterns[j]->pattern + current_size),
+					buf, (patterns[j]->mask + current_size),
+					(patterns[j]->size - current_size))) {
+
+					/*
+					 * pattern found using prefix at the
+					 * very beginning of the buffer, so
+					 * offset is 0, but we already zeroed
+					 * everything in the beginning of the
+					 * function. that's why the next line
+					 * is commented.
+					 */
+					/* results->info[found].offset = 0; */
+					results->info[found].type =
+							patterns[j]->type;
+					results->info[found].used_prefix_size =
+							current_size;
+					found++;
+					/*
+					 * save offset to start looking from
+					 * in the buffer, to avoid reusing the
+					 * data of a pattern we already found.
+					 */
+					start_offset = (patterns[j]->size -
+							current_size);
+
+					if (found >= DVB_DMX_MAX_FOUND_PATTERNS)
+						goto next_prefix_lookup;
+					/*
+					 * we don't want to search for the same
+					 * pattern with several possible prefix
+					 * sizes if we have already found it,
+					 * so we break from the inner loop.
+					 * since we incremented 'found', we
+					 * will not search for additional
+					 * patterns using a prefix - that would
+					 * imply ambiguous patterns where one
+					 * pattern can be included in another.
+					 * the for loop will exit.
+					 */
+					break;
+				}
+			}
+			prefix &= ~(0x1 << (current_size - 1));
+			current_size--;
+		}
+	}
+
+	/*
+	 * Search buffer for entire pattern, starting with the string.
+	 * Note the external for loop does not execute if buf_size is
+	 * smaller than string_size (the cast to int is required, since
+	 * size_t is unsigned).
+	 */
+	for (i = start_offset; i < (int)(buf_size - string_size + 1); i++) {
+		if (dvb_dmx_patterns_match(string, (buf + i), string_mask,
+							string_size)) {
+			/* now search for patterns: */
+			for (j = 0; j < patterns_num; j++) {
+				/* avoid overflow to next buffer */
+				if ((i + patterns[j]->size) > buf_size)
+					continue;
+
+				if (dvb_dmx_patterns_match(
+					(patterns[j]->pattern + string_size),
+					(buf + i + string_size),
+					(patterns[j]->mask + string_size),
+					(patterns[j]->size - string_size))) {
+
+					results->info[found].offset = i;
+					results->info[found].type =
+						patterns[j]->type;
+					/*
+					 * save offset to start next prefix
+					 * lookup, to avoid reusing the data
+					 * of any pattern we already found.
+					 */
+					if ((i + patterns[j]->size) >
+							start_offset)
+						start_offset = (i +
+							patterns[j]->size);
+					/*
+					 * did not use a prefix to find this
+					 * pattern, but we zeroed everything
+					 * in the beginning of the function.
+					 * So no need to zero used_prefix_size
+					 * for results->info[found]
+					 */
+
+					found++;
+					if (found >= DVB_DMX_MAX_FOUND_PATTERNS)
+						goto next_prefix_lookup;
+					/*
+					 * theoretically we don't have to break
+					 * here, but we don't want to search
+					 * for the other matching patterns on
+					 * the very same same place in the
+					 * buffer. That would mean the
+					 * (pattern & mask) combinations are
+					 * not unique. So we break from inner
+					 * loop and move on to the next place
+					 * in the buffer.
+					 */
+					break;
+				}
+			}
+		}
+	}
+
+next_prefix_lookup:
+	/* check for possible prefix sizes for the next buffer */
+	for (j = 0; j < patterns_num; j++) {
+		prefix_size_masks->size_mask[j] = 0;
+		for (i = 1; i < patterns[j]->size; i++) {
+			/*
+			 * avoid looking outside of the buffer
+			 * or reusing previously used data.
+			 */
+			if (i > (buf_size - start_offset))
+				break;
+
+			if (dvb_dmx_patterns_match(patterns[j]->pattern,
+					(buf + buf_size - i),
+					patterns[j]->mask, i)) {
+				prefix_size_masks->size_mask[j] |=
+						(1 << (i - 1));
+			}
+		}
+	}
+
+	return found;
+}
+EXPORT_SYMBOL(dvb_dmx_video_pattern_search);
+
 static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
 					   const u8 *buf)
 {
@@ -434,6 +749,374 @@
 	return 0;
 }
 
+static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed,
+		struct dmx_index_event_info *idx_event,
+		int traverse_from_tail)
+{
+	struct dmx_index_entry *idx_entry;
+	struct dmx_index_entry *curr_entry;
+	struct list_head *pos;
+
+	/* get entry from free list */
+	if (list_empty(&feed->rec_info->idx_info.free_list)) {
+		printk(KERN_ERR "%s: index free list is empty\n", __func__);
+		return -ENOMEM;
+	}
+
+	idx_entry = list_first_entry(&feed->rec_info->idx_info.free_list,
+					struct dmx_index_entry, next);
+	list_del(&idx_entry->next);
+
+	idx_entry->event = *idx_event;
+
+	pos = &feed->rec_info->idx_info.ready_list;
+	if (traverse_from_tail) {
+		list_for_each_entry_reverse(curr_entry,
+			&feed->rec_info->idx_info.ready_list, next) {
+			if (curr_entry->event.match_tsp_num <=
+				idx_event->match_tsp_num) {
+				pos = &curr_entry->next;
+				break;
+			}
+		}
+	} else {
+		list_for_each_entry(curr_entry,
+			&feed->rec_info->idx_info.ready_list, next) {
+			if (curr_entry->event.match_tsp_num >
+				idx_event->match_tsp_num) {
+				pos = &curr_entry->next;
+				break;
+			}
+		}
+	}
+
+	if (traverse_from_tail)
+		list_add(&idx_entry->next, pos);
+	else
+		list_add_tail(&idx_entry->next, pos);
+
+	return 0;
+}
+
+int dvb_demux_push_idx_event(struct dvb_demux_feed *feed,
+		struct dmx_index_event_info *idx_event)
+{
+	int ret;
+
+	spin_lock(&feed->demux->lock);
+	ret = dvb_demux_save_idx_event(feed, idx_event, 1);
+	spin_unlock(&feed->demux->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_demux_push_idx_event);
+
+static inline void dvb_dmx_notify_indexing(struct dvb_demux_feed *feed)
+{
+	struct dmx_data_ready dmx_data_ready;
+	struct dmx_index_entry *curr_entry;
+	struct list_head *n, *pos;
+
+	dmx_data_ready.status = DMX_OK_IDX;
+
+	list_for_each_safe(pos, n, &feed->rec_info->idx_info.ready_list) {
+		curr_entry = list_entry(pos, struct dmx_index_entry, next);
+
+		if ((feed->rec_info->idx_info.min_pattern_tsp_num == (u64)-1) ||
+			(curr_entry->event.match_tsp_num <=
+			 feed->rec_info->idx_info.min_pattern_tsp_num)) {
+			dmx_data_ready.idx_event = curr_entry->event;
+			feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+			list_del(&curr_entry->next);
+			list_add_tail(&curr_entry->next,
+				&feed->rec_info->idx_info.free_list);
+		}
+	}
+}
+
+void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed)
+{
+	spin_lock(&feed->demux->lock);
+	dvb_dmx_notify_indexing(feed);
+	spin_unlock(&feed->demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_notify_idx_events);
+
+static void dvb_dmx_process_pattern_result(struct dvb_demux_feed *feed,
+		struct dvb_dmx_video_patterns_results *patterns, int pattern,
+		u64 curr_stc, u64 prev_stc,
+		u64 curr_match_tsp, u64 prev_match_tsp,
+		u64 curr_pusi_tsp, u64 prev_pusi_tsp)
+{
+	int mpeg_frame_start;
+	int h264_frame_start;
+	int vc1_frame_start;
+	int seq_start;
+	u64 frame_end_in_seq;
+	struct dmx_index_event_info idx_event;
+
+	idx_event.pid = feed->pid;
+	if (patterns->info[pattern].used_prefix_size) {
+		idx_event.match_tsp_num = prev_match_tsp;
+		idx_event.last_pusi_tsp_num = prev_pusi_tsp;
+		idx_event.stc = prev_stc;
+	} else {
+		idx_event.match_tsp_num = curr_match_tsp;
+		idx_event.last_pusi_tsp_num = curr_pusi_tsp;
+		idx_event.stc = curr_stc;
+	}
+
+	/* notify on frame-end if needed */
+	if (feed->prev_frame_valid) {
+		if (feed->prev_frame_type & DMX_IDX_MPEG_I_FRAME_START) {
+			idx_event.type = DMX_IDX_MPEG_I_FRAME_END;
+			frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_MPEG_P_FRAME_START) {
+			idx_event.type = DMX_IDX_MPEG_P_FRAME_END;
+			frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_MPEG_B_FRAME_START) {
+			idx_event.type = DMX_IDX_MPEG_B_FRAME_END;
+			frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_H264_IDR_START) {
+			idx_event.type = DMX_IDX_H264_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_H264_NON_IDR_START) {
+			idx_event.type = DMX_IDX_H264_NON_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else {
+			idx_event.type = DMX_IDX_VC1_FRAME_END;
+			frame_end_in_seq = DMX_IDX_VC1_FIRST_SEQ_FRAME_END;
+		}
+
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+
+		if (feed->first_frame_in_seq_notified &&
+			feed->idx_params.types & frame_end_in_seq) {
+			idx_event.type = frame_end_in_seq;
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+			feed->first_frame_in_seq_notified = 0;
+		}
+	}
+
+	seq_start = patterns->info[pattern].type &
+		(DMX_IDX_MPEG_SEQ_HEADER | DMX_IDX_H264_SPS |
+		 DMX_IDX_VC1_SEQ_HEADER);
+
+	/* did we find start of sequence/SPS? */
+	if (seq_start) {
+		feed->first_frame_in_seq = 1;
+		feed->first_frame_in_seq_notified = 0;
+		feed->prev_frame_valid = 0;
+		idx_event.type = patterns->info[pattern].type;
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+		return;
+	}
+
+	mpeg_frame_start = patterns->info[pattern].type &
+		(DMX_IDX_MPEG_I_FRAME_START |
+		 DMX_IDX_MPEG_P_FRAME_START |
+		 DMX_IDX_MPEG_B_FRAME_START);
+
+	h264_frame_start = patterns->info[pattern].type &
+		(DMX_IDX_H264_IDR_START | DMX_IDX_H264_NON_IDR_START);
+
+	vc1_frame_start = patterns->info[pattern].type &
+		DMX_IDX_VC1_FRAME_START;
+
+	if (!mpeg_frame_start && !h264_frame_start && !vc1_frame_start) {
+		/* neither sequence nor frame, notify on the entry if needed */
+		idx_event.type = patterns->info[pattern].type;
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+		feed->prev_frame_valid = 0;
+		return;
+	}
+
+	/* notify on first frame in sequence/sps if needed */
+	if (feed->first_frame_in_seq) {
+		feed->first_frame_in_seq = 0;
+		feed->first_frame_in_seq_notified = 1;
+		if (mpeg_frame_start)
+			idx_event.type = DMX_IDX_MPEG_FIRST_SEQ_FRAME_START;
+		else if (h264_frame_start)
+			idx_event.type = DMX_IDX_H264_FIRST_SPS_FRAME_START;
+		else
+			idx_event.type = DMX_IDX_VC1_FIRST_SEQ_FRAME_START;
+
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+	}
+
+	/* notify on frame start if needed */
+	idx_event.type = patterns->info[pattern].type;
+	if (feed->idx_params.types & idx_event.type)
+		dvb_demux_save_idx_event(feed, &idx_event, 1);
+
+	feed->prev_frame_valid = 1;
+	feed->prev_frame_type = patterns->info[pattern].type;
+}
+
+void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed,
+		struct dvb_dmx_video_patterns_results *patterns, int pattern,
+		u64 curr_stc, u64 prev_stc,
+		u64 curr_match_tsp, u64 prev_match_tsp,
+		u64 curr_pusi_tsp, u64 prev_pusi_tsp)
+{
+	spin_lock(&feed->demux->lock);
+	dvb_dmx_process_pattern_result(feed,
+		patterns, pattern,
+		curr_stc, prev_stc,
+		curr_match_tsp, prev_match_tsp,
+		curr_pusi_tsp, prev_pusi_tsp);
+	spin_unlock(&feed->demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_process_idx_pattern);
+
+static void dvb_dmx_index(struct dvb_demux_feed *feed,
+		const u8 *buf,
+		const u8 timestamp[TIMESTAMP_LEN])
+{
+	int i;
+	int p;
+	u64 stc;
+	int found_patterns;
+	int count = payload(buf);
+	u64 min_pattern_tsp_num;
+	struct dvb_demux_feed *tmp_feed;
+	struct dvb_demux *demux = feed->demux;
+	struct dmx_index_event_info idx_event;
+	struct dvb_dmx_video_patterns_results patterns;
+
+	if (feed->demux->convert_ts)
+		feed->demux->convert_ts(feed, timestamp, &stc);
+	else
+		stc = 0;
+
+	idx_event.pid = feed->pid;
+	idx_event.stc = stc;
+	idx_event.match_tsp_num = feed->rec_info->ts_output_count;
+
+	/* PUSI ? */
+	if (buf[1] & 0x40) {
+		feed->curr_pusi_tsp_num = feed->rec_info->ts_output_count;
+		if (feed->idx_params.types & DMX_IDX_PUSI) {
+			idx_event.type = DMX_IDX_PUSI;
+			idx_event.last_pusi_tsp_num =
+				feed->curr_pusi_tsp_num;
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+		}
+	}
+
+	/*
+	 * if we still did not encounter a TS packet with PUSI indication,
+	 * we cannot report index entries yet as we need to provide
+	 * the TS packet number with PUSI indication preceeding the TS
+	 * packet pointed by the reported index entry.
+	 */
+	if (feed->curr_pusi_tsp_num == (u64)-1) {
+		dvb_dmx_notify_indexing(feed);
+		return;
+	}
+
+	if ((feed->idx_params.types & DMX_IDX_RAI) && /* index RAI? */
+		(buf[3] & 0x20) && /* adaptation field exists? */
+		(buf[4] > 0) && /* adaptation field len > 0 ? */
+		(buf[5] & 0x40)) { /* RAI is set? */
+		idx_event.type = DMX_IDX_RAI;
+		idx_event.last_pusi_tsp_num =
+			feed->curr_pusi_tsp_num;
+		dvb_demux_save_idx_event(feed, &idx_event, 1);
+	}
+
+	/*
+	 * if no pattern search is required, or the TS packet has no payload,
+	 * pattern search is not executed.
+	 */
+	if (!feed->pattern_num || !count) {
+		dvb_dmx_notify_indexing(feed);
+		return;
+	}
+
+	p = 188 - count; /* payload start */
+
+	found_patterns =
+		dvb_dmx_video_pattern_search(feed->patterns,
+				feed->pattern_num, &buf[p], count,
+				&feed->prefix_size, &patterns);
+
+	for (i = 0; i < found_patterns; i++)
+		dvb_dmx_process_pattern_result(feed, &patterns, i,
+			stc, feed->prev_stc,
+			feed->rec_info->ts_output_count, feed->prev_tsp_num,
+			feed->curr_pusi_tsp_num, feed->prev_pusi_tsp_num);
+
+	feed->prev_tsp_num = feed->rec_info->ts_output_count;
+	feed->prev_pusi_tsp_num = feed->curr_pusi_tsp_num;
+	feed->prev_stc = stc;
+	feed->last_pattern_tsp_num = feed->rec_info->ts_output_count;
+
+	/*
+	 * it is possible to have a TS packet that has a prefix of
+	 * a video pattern but the video pattern is not identified yet
+	 * until we get the next TS packet of that PID. When we get
+	 * the next TS packet of that PID, pattern-search would
+	 * detect that we have a new index entry that starts in the
+	 * previous TS packet.
+	 * In order to notify the user on index entries with match_tsp_num
+	 * in ascending order, index events with match_tsp_num up to
+	 * the last_pattern_tsp_num are notified now to the user,
+	 * the rest can't be notified now as we might hit the above
+	 * scenario and cause the events not to be notified with
+	 * ascending order of match_tsp_num.
+	 */
+	if (feed->rec_info->idx_info.pattern_search_feeds_num == 1) {
+		/*
+		 * optimization for case we have only one PID
+		 * with video pattern search, in this case
+		 * min_pattern_tsp_num is simply updated to the new
+		 * TS packet number of the PID with pattern search.
+		 */
+		feed->rec_info->idx_info.min_pattern_tsp_num =
+			feed->last_pattern_tsp_num;
+		dvb_dmx_notify_indexing(feed);
+		return;
+	}
+
+	/*
+	 * if we have more than one PID with pattern search,
+	 * min_pattern_tsp_num needs to be updated now based on
+	 * last_pattern_tsp_num of all PIDs with pattern search.
+	 */
+	min_pattern_tsp_num = (u64)-1;
+	i = feed->rec_info->idx_info.pattern_search_feeds_num;
+	list_for_each_entry(tmp_feed, &demux->feed_list, list_head) {
+		if ((tmp_feed->state != DMX_STATE_GO) ||
+			(tmp_feed->type != DMX_TYPE_TS) ||
+			(tmp_feed->feed.ts.buffer.ringbuff !=
+			 feed->feed.ts.buffer.ringbuff))
+			continue;
+
+		if ((tmp_feed->last_pattern_tsp_num != (u64)-1) &&
+			((min_pattern_tsp_num == (u64)-1) ||
+			 (tmp_feed->last_pattern_tsp_num <
+			  min_pattern_tsp_num)))
+			min_pattern_tsp_num = tmp_feed->last_pattern_tsp_num;
+
+		if (tmp_feed->pattern_num) {
+			i--;
+			if (i == 0)
+				break;
+		}
+	}
+
+	feed->rec_info->idx_info.min_pattern_tsp_num = min_pattern_tsp_num;
+
+	/* notify all index entries up to min_pattern_tsp_num */
+	dvb_dmx_notify_indexing(feed);
+}
+
 static inline void dvb_dmx_swfilter_output_packet(
 	struct dvb_demux_feed *feed,
 	const u8 *buf,
@@ -456,6 +1139,11 @@
 	if (feed->tsp_out_format == DMX_TSP_FORMAT_192_TAIL)
 		feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL,
 			0, &feed->feed.ts, DMX_OK);
+
+	if (feed->idx_params.enable)
+		dvb_dmx_index(feed, buf, timestamp);
+
+	feed->rec_info->ts_output_count++;
 }
 
 static inline void dvb_dmx_configure_decoder_fullness(
@@ -633,7 +1321,7 @@
 	((f)->feed.ts.is_filtering) &&					\
 	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
 
-void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+static void dvb_dmx_swfilter_one_packet(struct dvb_demux *demux, const u8 *buf,
 				const u8 timestamp[TIMESTAMP_LEN])
 {
 	struct dvb_demux_feed *feed;
@@ -713,6 +1401,14 @@
 			dvb_dmx_swfilter_output_packet(feed, buf, timestamp);
 	}
 }
+
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+				const u8 timestamp[TIMESTAMP_LEN])
+{
+	spin_lock(&demux->lock);
+	dvb_dmx_swfilter_one_packet(demux, buf, timestamp);
+	spin_unlock(&demux->lock);
+}
 EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
 
 void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
@@ -777,7 +1473,7 @@
 
 	while (count--) {
 		if (buf[0] == 0x47)
-			dvb_dmx_swfilter_packet(demux, buf, timestamp);
+			dvb_dmx_swfilter_one_packet(demux, buf, timestamp);
 		buf += 188;
 	}
 
@@ -857,10 +1553,11 @@
 		if (pktsize == 192 &&
 			leadingbytes &&
 			demux->tsbuf[leadingbytes] == 0x47)  /* double check */
-			dvb_dmx_swfilter_packet(demux,
+			dvb_dmx_swfilter_one_packet(demux,
 				demux->tsbuf + TIMESTAMP_LEN, timestamp);
 		else if (demux->tsbuf[0] == 0x47) /* double check */
-			dvb_dmx_swfilter_packet(demux, demux->tsbuf, timestamp);
+			dvb_dmx_swfilter_one_packet(demux,
+					demux->tsbuf, timestamp);
 		demux->tsbufp = 0;
 		p += j;
 	}
@@ -889,13 +1586,13 @@
 				q = &buf[p+leadingbytes];
 				memcpy(timestamp, &buf[p], TIMESTAMP_LEN);
 			} else {
-				memcpy(timestamp, &buf[188], TIMESTAMP_LEN);
+				memcpy(timestamp, &buf[p+188], TIMESTAMP_LEN);
 			}
 		} else {
 			memset(timestamp, 0, TIMESTAMP_LEN);
 		}
 
-		dvb_dmx_swfilter_packet(demux, q, timestamp);
+		dvb_dmx_swfilter_one_packet(demux, q, timestamp);
 		p += pktsize;
 	}
 
@@ -990,6 +1687,249 @@
 	return &demux->feed[i];
 }
 
+const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern)
+{
+	switch (dmx_idx_pattern) {
+	case DMX_IDX_MPEG_SEQ_HEADER:
+		return &mpeg2_seq_hdr;
+
+	case DMX_IDX_MPEG_GOP:
+		return &mpeg2_gop;
+
+	case DMX_IDX_MPEG_I_FRAME_START:
+		return &mpeg2_iframe;
+
+	case DMX_IDX_MPEG_P_FRAME_START:
+		return &mpeg2_pframe;
+
+	case DMX_IDX_MPEG_B_FRAME_START:
+		return &mpeg2_bframe;
+
+	case DMX_IDX_H264_SPS:
+		return &h264_sps;
+
+	case DMX_IDX_H264_PPS:
+		return &h264_pps;
+
+	case DMX_IDX_H264_IDR_START:
+		return &h264_idr;
+
+	case DMX_IDX_H264_NON_IDR_START:
+		return &h264_non_idr;
+
+	case DMX_IDX_VC1_SEQ_HEADER:
+		return &vc1_seq_hdr;
+
+	case DMX_IDX_VC1_ENTRY_POINT:
+		return &vc1_entry_point;
+
+	case DMX_IDX_VC1_FRAME_START:
+		return &vc1_frame;
+
+	default:
+		return NULL;
+	}
+}
+EXPORT_SYMBOL(dvb_dmx_get_pattern);
+
+static void dvb_dmx_init_idx_state(struct dvb_demux_feed *feed)
+{
+	feed->prev_tsp_num = (u64)-1;
+	feed->curr_pusi_tsp_num = (u64)-1;
+	feed->prev_pusi_tsp_num = (u64)-1;
+	feed->prev_frame_valid = 0;
+	feed->first_frame_in_seq = 0;
+	feed->first_frame_in_seq_notified = 0;
+	feed->last_pattern_tsp_num = (u64)-1;
+	feed->pattern_num = 0;
+	memset(&feed->prefix_size, 0,
+		sizeof(struct dvb_dmx_video_prefix_size_masks));
+
+	if (feed->idx_params.types &
+		(DMX_IDX_MPEG_SEQ_HEADER |
+		 DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		 DMX_IDX_MPEG_FIRST_SEQ_FRAME_END)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_MPEG_GOP)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP);
+		feed->pattern_num++;
+	}
+
+	/* MPEG2 I-frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_MPEG_I_FRAME_START | DMX_IDX_MPEG_I_FRAME_END |
+		  DMX_IDX_MPEG_P_FRAME_END | DMX_IDX_MPEG_B_FRAME_END |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	/* MPEG2 P-frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_MPEG_P_FRAME_START | DMX_IDX_MPEG_P_FRAME_END |
+		  DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_B_FRAME_END |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	/* MPEG2 B-frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_MPEG_B_FRAME_START | DMX_IDX_MPEG_B_FRAME_END |
+		  DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_P_FRAME_END |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_SPS |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_SPS);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_H264_PPS)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_PPS);
+		feed->pattern_num++;
+	}
+
+	/* H264 IDR */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_IDR_START | DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START);
+		feed->pattern_num++;
+	}
+
+	/* H264 non-IDR */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_NON_IDR_START | DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_VC1_SEQ_HEADER |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_VC1_ENTRY_POINT)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT);
+		feed->pattern_num++;
+	}
+
+	/* VC1 frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_VC1_FRAME_START | DMX_IDX_VC1_FRAME_END |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	if (feed->pattern_num)
+		feed->rec_info->idx_info.pattern_search_feeds_num++;
+}
+
+static struct dvb_demux_rec_info *dvb_dmx_alloc_rec_info(
+					struct dmx_ts_feed *ts_feed)
+{
+	int i;
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	struct dvb_demux_rec_info *rec_info;
+	struct dvb_demux_feed *tmp_feed;
+
+	/* check if this feed share recording buffer with other active feeds */
+	list_for_each_entry(tmp_feed, &demux->feed_list, list_head) {
+		if ((tmp_feed->state == DMX_STATE_GO) &&
+			(tmp_feed->type == DMX_TYPE_TS) &&
+			(tmp_feed != feed) &&
+			(tmp_feed->feed.ts.buffer.ringbuff ==
+			 ts_feed->buffer.ringbuff)) {
+			/* indexing information is shared between the feeds */
+			tmp_feed->rec_info->ref_count++;
+			return tmp_feed->rec_info;
+		}
+	}
+
+	/* Need to allocate a new indexing info */
+	for (i = 0; i < demux->feednum; i++)
+		if (!demux->rec_info_pool[i].ref_count)
+			break;
+
+	if (i == demux->feednum)
+		return NULL;
+
+	rec_info = &demux->rec_info_pool[i];
+	rec_info->ref_count++;
+	INIT_LIST_HEAD(&rec_info->idx_info.free_list);
+	INIT_LIST_HEAD(&rec_info->idx_info.ready_list);
+
+	for (i = 0; i < DMX_IDX_EVENT_QUEUE_SIZE; i++)
+		list_add(&rec_info->idx_info.events[i].next,
+			&rec_info->idx_info.free_list);
+
+	rec_info->ts_output_count = 0;
+	rec_info->idx_info.min_pattern_tsp_num = (u64)-1;
+	rec_info->idx_info.pattern_search_feeds_num = 0;
+
+	return rec_info;
+}
+
+static void dvb_dmx_free_rec_info(struct dmx_ts_feed *ts_feed)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+	if (!feed->rec_info || !feed->rec_info->ref_count) {
+		printk(KERN_ERR "%s: invalid idx info state\n", __func__);
+		return;
+	}
+
+	feed->rec_info->ref_count--;
+
+	return;
+}
+
 static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
 {
 	struct dvb_demux_feed *entry;
@@ -1105,7 +2045,22 @@
 
 	feed->first_cc = 1;
 
+	if ((feed->ts_type & TS_PACKET) &&
+		!(feed->ts_type & TS_PAYLOAD_ONLY)) {
+		feed->rec_info = dvb_dmx_alloc_rec_info(ts_feed);
+		if (!feed->rec_info) {
+			mutex_unlock(&demux->mutex);
+			return -ENOMEM;
+		}
+		dvb_dmx_init_idx_state(feed);
+	} else {
+		feed->pattern_num = 0;
+		feed->rec_info = NULL;
+	}
+
 	if ((ret = demux->start_feed(feed)) < 0) {
+		dvb_dmx_free_rec_info(ts_feed);
+		feed->rec_info = NULL;
 		mutex_unlock(&demux->mutex);
 		return ret;
 	}
@@ -1143,6 +2098,14 @@
 	ts_feed->is_filtering = 0;
 	feed->state = DMX_STATE_ALLOCATED;
 	spin_unlock_irq(&demux->lock);
+
+	if (feed->rec_info) {
+		if (feed->pattern_num)
+			feed->rec_info->idx_info.pattern_search_feeds_num--;
+		dvb_dmx_free_rec_info(ts_feed);
+		feed->rec_info = NULL;
+	}
+
 	mutex_unlock(&demux->mutex);
 
 	return ret;
@@ -1242,14 +2205,41 @@
 	return ret;
 }
 
-static int dmx_ts_set_indexing_params(
+static int dmx_ts_set_video_codec(
 	struct dmx_ts_feed *ts_feed,
-	struct dmx_indexing_video_params *params)
+	enum dmx_video_codec video_codec)
 {
 	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
 
-	memcpy(&feed->indexing_params, params,
-			sizeof(struct dmx_indexing_video_params));
+	feed->video_codec = video_codec;
+
+	return 0;
+}
+
+static int dmx_ts_set_idx_params(struct dmx_ts_feed *ts_feed,
+	struct dmx_indexing_params *idx_params)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *dvbdmx = feed->demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if ((feed->state == DMX_STATE_GO) &&
+		!feed->rec_info) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+	feed->idx_params = *idx_params;
+
+	if (feed->state == DMX_STATE_GO) {
+		spin_lock_irq(&dvbdmx->lock);
+		if (feed->pattern_num)
+			feed->rec_info->idx_info.pattern_search_feeds_num--;
+		dvb_dmx_init_idx_state(feed);
+		spin_unlock_irq(&dvbdmx->lock);
+	}
+
+	mutex_unlock(&dvbdmx->mutex);
 
 	return 0;
 }
@@ -1386,8 +2376,7 @@
 	feed->secure_mode.is_secured = 0;
 	feed->buffer = NULL;
 	feed->tsp_out_format = DMX_TSP_FORMAT_188;
-	memset(&feed->indexing_params, 0,
-			sizeof(struct dmx_indexing_video_params));
+	feed->idx_params.enable = 0;
 
 	/* default behaviour - pass first PES data even if it is
 	 * partial PES data from previous PES that we didn't receive its header.
@@ -1403,7 +2392,8 @@
 	(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
 	(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
 	(*ts_feed)->set = dmx_ts_feed_set;
-	(*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
+	(*ts_feed)->set_video_codec = dmx_ts_set_video_codec;
+	(*ts_feed)->set_idx_params = dmx_ts_set_idx_params;
 	(*ts_feed)->set_tsp_out_format = dmx_ts_set_tsp_out_format;
 	(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
 	(*ts_feed)->reuse_decoder_buffer = dmx_ts_feed_reuse_decoder_buffer;
@@ -2017,6 +3007,16 @@
 		return -ENOMEM;
 	}
 
+	dvbdemux->rec_info_pool = vmalloc(dvbdemux->feednum *
+		sizeof(struct dvb_demux_rec_info));
+	if (!dvbdemux->rec_info_pool) {
+		vfree(dvbdemux->feed);
+		vfree(dvbdemux->filter);
+		dvbdemux->feed = NULL;
+		dvbdemux->filter = NULL;
+		return -ENOMEM;
+	}
+
 	dvbdemux->total_process_time = 0;
 	dvbdemux->total_crc_time = 0;
 	snprintf(dvbdemux->alias,
@@ -2045,9 +3045,12 @@
 		dvbdemux->filter[i].state = DMX_STATE_FREE;
 		dvbdemux->filter[i].index = i;
 	}
+
 	for (i = 0; i < dvbdemux->feednum; i++) {
 		dvbdemux->feed[i].state = DMX_STATE_FREE;
 		dvbdemux->feed[i].index = i;
+
+		dvbdemux->rec_info_pool[i].ref_count = 0;
 	}
 
 	dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
@@ -2117,6 +3120,7 @@
 	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
+	vfree(dvbdemux->rec_info_pool);
 }
 
 EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index fc04219..879aad2 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -69,6 +69,88 @@
 
 #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
 
+
+struct dmx_index_entry {
+	struct dmx_index_event_info event;
+	struct list_head next;
+};
+
+#define DMX_IDX_EVENT_QUEUE_SIZE	100
+struct dvb_demux_rec_info {
+	/* Reference counter for number of feeds using this information */
+	int ref_count;
+
+	/* Counter for number of TS packets output to recording buffer */
+	u64 ts_output_count;
+
+	/* Indexing information */
+	struct {
+		/*
+		 * Minimum TS packet number encountered in recording filter
+		 * among all feeds that search for video patterns
+		 */
+		u64 min_pattern_tsp_num;
+
+		/* Number of feeds with video pattern search request */
+		u8 pattern_search_feeds_num;
+
+		/* Index entries pool */
+		struct dmx_index_entry events[DMX_IDX_EVENT_QUEUE_SIZE];
+
+		/* List of free entries that can be used for new index events */
+		struct list_head free_list;
+
+		/* List holding ready index entries not notified to user yet */
+		struct list_head ready_list;
+	} idx_info;
+};
+
+#define DVB_DMX_MAX_PATTERN_LEN			6
+struct dvb_dmx_video_patterns {
+	/* the byte pattern to look for */
+	u8 pattern[DVB_DMX_MAX_PATTERN_LEN];
+
+	/* the byte mask to use (same length as pattern) */
+	u8 mask[DVB_DMX_MAX_PATTERN_LEN];
+
+	/* the length of the pattern, in bytes */
+	size_t size;
+
+	/* the type of the pattern. One of DMX_IDX_* definitions */
+	u64 type;
+};
+
+#define DVB_DMX_MAX_FOUND_PATTERNS					20
+#define DVB_DMX_MAX_SEARCH_PATTERN_NUM				20
+struct dvb_dmx_video_prefix_size_masks {
+	/*
+	 * a bit mask (per pattern) of possible prefix sizes to use
+	 * when searching for a pattern that started in the previous TS packet.
+	 * Updated by dvb_dmx_video_pattern_search for use in the next lookup.
+	 */
+	u32 size_mask[DVB_DMX_MAX_FOUND_PATTERNS];
+};
+
+struct dvb_dmx_video_patterns_results {
+	struct {
+		/*
+		 * The offset in the buffer where the pattern was found.
+		 * If a pattern is found using a prefix (i.e. started on the
+		 * previous buffer), offset is zero.
+		 */
+		u32 offset;
+
+		/*
+		 * The type of the pattern found.
+		 * One of DMX_IDX_* definitions.
+		 */
+		u64 type;
+
+		/* The prefix size that was used to find this pattern */
+		u32 used_prefix_size;
+	} info[DVB_DMX_MAX_FOUND_PATTERNS];
+};
+
 struct dvb_demux_feed {
 	union {
 		struct dmx_ts_feed ts;
@@ -105,6 +187,21 @@
 	int first_cc;
 	int pusi_seen;		/* prevents feeding of garbage from previous section */
 
+	struct dvb_demux_rec_info *rec_info;
+	u64 prev_tsp_num;
+	u64 prev_stc;
+	u64 curr_pusi_tsp_num;
+	u64 prev_pusi_tsp_num;
+	int prev_frame_valid;
+	u64 prev_frame_type;
+	int first_frame_in_seq;
+	int first_frame_in_seq_notified;
+	u64 last_pattern_tsp_num;
+	int pattern_num;
+	const struct dvb_dmx_video_patterns
+		*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
+	struct dvb_dmx_video_prefix_size_masks prefix_size;
+
 	u32 peslen;
 	u32 pes_tei_counter;
 	u32 pes_cont_err_counter;
@@ -113,7 +210,8 @@
 	struct list_head list_head;
 	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
 
-	struct dmx_indexing_video_params indexing_params;
+	enum dmx_video_codec video_codec;
+	struct dmx_indexing_params idx_params;
 };
 
 struct dvb_demux {
@@ -141,6 +239,9 @@
 			 const u8 *src, size_t len);
 	int (*oob_command)(struct dvb_demux_feed *feed,
 		struct dmx_oob_command *cmd);
+	void (*convert_ts)(struct dvb_demux_feed *feed,
+			 const u8 timestamp[TIMESTAMP_LEN],
+			 u64 *timestampIn27Mhz);
 
 	int users;
 #define MAX_DVB_DEMUX_USERS 10
@@ -178,6 +279,8 @@
 		dmx_section_fullness sec;
 	} buffer_ctrl;
 
+	struct dvb_demux_rec_info *rec_info_pool;
+
 	/*
 	 * the following is used for debugfs exposing info
 	 * about dvb demux performance.
@@ -204,6 +307,22 @@
 			enum dmx_tsp_format_t tsp_format);
 void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
 				const u8 timestamp[TIMESTAMP_LEN]);
+const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern);
+int dvb_dmx_video_pattern_search(
+		const struct dvb_dmx_video_patterns
+			*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM],
+		int patterns_num,
+		const u8 *buf, size_t buf_size,
+		struct dvb_dmx_video_prefix_size_masks *prefix_size_masks,
+		struct dvb_dmx_video_patterns_results *results);
+int dvb_demux_push_idx_event(struct dvb_demux_feed *feed,
+		struct dmx_index_event_info *idx_event);
+void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed,
+		struct dvb_dmx_video_patterns_results *patterns, int pattern,
+		u64 curr_stc, u64 prev_stc,
+		u64 curr_match_tsp, u64 prev_match_tsp,
+		u64 curr_pusi_tsp, u64 prev_pusi_tsp);
+void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed);
 
 /**
  * dvb_dmx_is_video_feed - Returns whether the PES feed
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 802349a..71087d9 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -195,9 +195,18 @@
 static int camera_v4l2_reqbufs(struct file *filep, void *fh,
 	struct v4l2_requestbuffers *req)
 {
+	int ret;
+	struct msm_session *session;
 	struct camera_v4l2_private *sp = fh_to_private(fh);
-
-	return vb2_reqbufs(&sp->vb2_q, req);
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+	session = msm_session_find(session_id);
+	if (WARN_ON(!session))
+		return -EIO;
+	mutex_lock(&session->lock);
+	ret = vb2_reqbufs(&sp->vb2_q, req);
+	mutex_unlock(&session->lock);
+	return ret;
 }
 
 static int camera_v4l2_querybuf(struct file *filep, void *fh,
@@ -209,17 +218,35 @@
 static int camera_v4l2_qbuf(struct file *filep, void *fh,
 	struct v4l2_buffer *pb)
 {
+	int ret;
+	struct msm_session *session;
 	struct camera_v4l2_private *sp = fh_to_private(fh);
-
-	return vb2_qbuf(&sp->vb2_q, pb);
+		struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+	session = msm_session_find(session_id);
+	if (WARN_ON(!session))
+		return -EIO;
+	mutex_lock(&session->lock);
+	ret = vb2_qbuf(&sp->vb2_q, pb);
+	mutex_unlock(&session->lock);
+	return ret;
 }
 
 static int camera_v4l2_dqbuf(struct file *filep, void *fh,
 	struct v4l2_buffer *pb)
 {
+	int ret;
+	struct msm_session *session;
 	struct camera_v4l2_private *sp = fh_to_private(fh);
-
-	return vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK);
+		struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+	session = msm_session_find(session_id);
+	if (WARN_ON(!session))
+		return -EIO;
+	mutex_lock(&session->lock);
+	ret = vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK);
+	mutex_unlock(&session->lock);
+	return ret;
 }
 
 static int camera_v4l2_streamon(struct file *filep, void *fh,
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 56ec259..9f1c81a 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -30,69 +30,6 @@
 #include "msm_vb2.h"
 #include "msm_sd.h"
 
-struct msm_queue_head {
-	struct list_head list;
-	spinlock_t lock;
-	int len;
-	int max;
-};
-
-/** msm_event:
- *
- *  event sent by imaging server
- **/
-struct msm_event {
-	struct video_device *vdev;
-	atomic_t on_heap;
-};
-
-struct msm_command {
-	struct list_head list;
-	struct v4l2_event event;
-	atomic_t on_heap;
-};
-
-/** struct msm_command_ack
- *
- *  Object of command_ack_q, which is
- *  created per open operation
- *
- *  contains struct msm_command
- **/
-struct msm_command_ack {
-	struct list_head list;
-	struct msm_queue_head command_q;
-	wait_queue_head_t wait;
-	int stream_id;
-};
-
-struct msm_v4l2_subdev {
-	/* FIXME: for session close and error handling such
-	 * as daemon shutdown */
-	int    close_sequence;
-};
-
-struct msm_session {
-	struct list_head list;
-
-	/* session index */
-	unsigned int session_id;
-
-	/* event queue sent by imaging server */
-	struct msm_event event_q;
-
-	/* ACK by imaging server. Object type of
-	 * struct msm_command_ack per open,
-	 * assumption is application can send
-	 * command on every opened video node */
-	struct msm_queue_head command_ack_q;
-
-	/* real streams(either data or metadate) owned by one
-	 * session struct msm_stream */
-	struct msm_queue_head stream_q;
-	struct mutex lock;
-};
-
 static struct v4l2_device *msm_v4l2_dev;
 
 static struct msm_queue_head *msm_session_q;
@@ -248,6 +185,17 @@
 	return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0;
 }
 
+
+struct msm_session *msm_session_find(unsigned int session_id)
+{
+	struct msm_session *session;
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (WARN_ON(!session))
+		return NULL;
+	return session;
+}
+
 int msm_create_stream(unsigned int session_id,
 	unsigned int stream_id, struct vb2_queue *q)
 {
@@ -492,7 +440,7 @@
 		list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
 			__msm_sd_close_session_streams(sd, sd_close);
 	spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
-
+	INIT_LIST_HEAD(&stream->queued_list);
 	return 0;
 }
 
@@ -709,7 +657,7 @@
 		msecs_to_jiffies(timeout));
 	if (list_empty_careful(&cmd_ack->command_q.list)) {
 		if (!rc) {
-			pr_err("%s: Ankit Timed out\n", __func__);
+			pr_err("%s: Timed out\n", __func__);
 			rc = -ETIMEDOUT;
 		}
 		if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index 39901ad..d57cf8d 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -38,6 +38,69 @@
 	atomic_t opened;
 };
 
+struct msm_queue_head {
+	struct list_head list;
+	spinlock_t lock;
+	int len;
+	int max;
+};
+
+/** msm_event:
+ *
+ *  event sent by imaging server
+ **/
+struct msm_event {
+	struct video_device *vdev;
+	atomic_t on_heap;
+};
+
+struct msm_command {
+	struct list_head list;
+	struct v4l2_event event;
+	atomic_t on_heap;
+};
+
+/** struct msm_command_ack
+ *
+ *  Object of command_ack_q, which is
+ *  created per open operation
+ *
+ *  contains struct msm_command
+ **/
+struct msm_command_ack {
+	struct list_head list;
+	struct msm_queue_head command_q;
+	wait_queue_head_t wait;
+	int stream_id;
+};
+
+struct msm_v4l2_subdev {
+	/* FIXME: for session close and error handling such
+	 * as daemon shutdown */
+	int    close_sequence;
+};
+
+struct msm_session {
+	struct list_head list;
+
+	/* session index */
+	unsigned int session_id;
+
+	/* event queue sent by imaging server */
+	struct msm_event event_q;
+
+	/* ACK by imaging server. Object type of
+	 * struct msm_command_ack per open,
+	 * assumption is application can send
+	 * command on every opened video node */
+	struct msm_queue_head command_ack_q;
+
+	/* real streams(either data or metadate) owned by one
+	 * session struct msm_stream */
+	struct msm_queue_head stream_q;
+	struct mutex lock;
+};
+
 int msm_post_event(struct v4l2_event *event, int timeout);
 int  msm_create_session(unsigned int session, struct video_device *vdev);
 int msm_destroy_session(unsigned int session_id);
@@ -52,5 +115,5 @@
 struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
 	unsigned int stream_id);
 struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
-
+struct msm_session *msm_session_find(unsigned int session_id);
 #endif /*_MSM_H */
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 29262af..8fa8f8d 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -48,7 +48,6 @@
 	}
 	msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf);
 	msm_vb2_buf->in_freeq = 0;
-	msm_vb2_buf->stream = stream;
 
 	return 0;
 }
@@ -66,7 +65,7 @@
 		return;
 	}
 
-	stream = msm_vb2->stream;
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
 	if (!stream) {
 		pr_err("%s:%d] NULL stream", __func__, __LINE__);
 		return;
@@ -91,7 +90,7 @@
 		return -EINVAL;
 	}
 
-	stream = msm_vb2->stream;
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
 	if (!stream) {
 		pr_err("%s:%d] NULL stream", __func__, __LINE__);
 		return -EINVAL;
@@ -122,7 +121,7 @@
 		return;
 	}
 
-	stream = msm_vb2->stream;
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
 	if (!stream) {
 		pr_err("%s:%d] NULL stream", __func__, __LINE__);
 		return;
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
index 027d344..7082f85 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
@@ -42,7 +42,6 @@
 	struct vb2_buffer vb2_buf;
 	struct list_head list;
 	int in_freeq;
-	struct msm_stream *stream;
 };
 
 struct msm_vb2_private_data {
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 1a481ce..431d35d 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
@@ -95,80 +95,6 @@
 static int mpq_sdmx_debug;
 module_param(mpq_sdmx_debug, int, S_IRUGO | S_IWUSR);
 
-
-/**
- * Maximum allowed framing pattern size
- */
-#define MPQ_MAX_PATTERN_SIZE				6
-
-/**
- * Number of patterns to look for when doing framing, per video standard
- */
-#define MPQ_MPEG2_PATTERN_NUM				5
-#define MPQ_H264_PATTERN_NUM				5
-#define MPQ_VC1_PATTERN_NUM				3
-
-/*
- * mpq_framing_pattern_lookup_params - framing pattern lookup parameters.
- *
- * @pattern: the byte pattern to look for.
- * @mask: the byte mask to use (same length as pattern).
- * @size: the length of the pattern, in bytes.
- * @type: the type of the pattern.
- */
-struct mpq_framing_pattern_lookup_params {
-	u8 pattern[MPQ_MAX_PATTERN_SIZE];
-	u8 mask[MPQ_MAX_PATTERN_SIZE];
-	size_t size;
-	enum dmx_framing_pattern_type type;
-};
-
-/*
- * Pre-defined video framing lookup pattern information.
- * Note: the first pattern in each patterns database must
- * be the Sequence Header (or equivalent SPS in H.264).
- * The code assumes this is the case when prepending
- * Sequence Header data in case it is required.
- */
-static const struct mpq_framing_pattern_lookup_params
-		mpeg2_patterns[MPQ_MPEG2_PATTERN_NUM] = {
-	{{0x00, 0x00, 0x01, 0xB3}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
-			DMX_FRM_MPEG2_SEQUENCE_HEADER},
-	{{0x00, 0x00, 0x01, 0xB8}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
-			DMX_FRM_MPEG2_GOP_HEADER},
-	{{0x00, 0x00, 0x01, 0x00, 0x00, 0x08},
-			{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, 6,
-			DMX_FRM_MPEG2_I_PIC},
-	{{0x00, 0x00, 0x01, 0x00, 0x00, 0x10},
-			{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, 6,
-			DMX_FRM_MPEG2_P_PIC},
-	{{0x00, 0x00, 0x01, 0x00, 0x00, 0x18},
-			{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, 6,
-			DMX_FRM_MPEG2_B_PIC}
-};
-
-static const struct mpq_framing_pattern_lookup_params
-		h264_patterns[MPQ_H264_PATTERN_NUM] = {
-	{{0x00, 0x00, 0x01, 0x07}, {0xFF, 0xFF, 0xFF, 0x1F}, 4,
-			DMX_FRM_H264_SPS},
-	{{0x00, 0x00, 0x01, 0x08}, {0xFF, 0xFF, 0xFF, 0x1F}, 4,
-			DMX_FRM_H264_PPS},
-	{{0x00, 0x00, 0x01, 0x05, 0x80}, {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, 5,
-			DMX_FRM_H264_IDR_PIC},
-	{{0x00, 0x00, 0x01, 0x01, 0x80}, {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, 5,
-			DMX_FRM_H264_NON_IDR_PIC}
-};
-
-static const struct mpq_framing_pattern_lookup_params
-		vc1_patterns[MPQ_VC1_PATTERN_NUM] = {
-	{{0x00, 0x00, 0x01, 0x0F}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
-			DMX_FRM_VC1_SEQUENCE_HEADER},
-	{{0x00, 0x00, 0x01, 0x0E}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
-			DMX_FRM_VC1_ENTRY_POINT_HEADER},
-	{{0x00, 0x00, 0x01, 0x0D}, {0xFF, 0xFF, 0xFF, 0xFF}, 4,
-			DMX_FRM_VC1_FRAME_START_CODE}
-};
-
 /* Global data-structure for managing demux devices */
 static struct
 {
@@ -211,312 +137,74 @@
 
 /* Check if a framing pattern is a video frame pattern or a header pattern */
 static inline int mpq_dmx_is_video_frame(
-				enum dmx_indexing_video_standard standard,
-				enum dmx_framing_pattern_type pattern_type)
+				enum dmx_video_codec codec,
+				u64 pattern_type)
 {
-	switch (standard) {
-	case DMX_INDEXING_MPEG2:
-		if ((pattern_type == DMX_FRM_MPEG2_I_PIC) ||
-			(pattern_type == DMX_FRM_MPEG2_P_PIC) ||
-			(pattern_type == DMX_FRM_MPEG2_B_PIC))
+	switch (codec) {
+	case DMX_VIDEO_CODEC_MPEG2:
+		if ((pattern_type == DMX_IDX_MPEG_I_FRAME_START) ||
+			(pattern_type == DMX_IDX_MPEG_P_FRAME_START) ||
+			(pattern_type == DMX_IDX_MPEG_B_FRAME_START))
 			return 1;
 		return 0;
-	case DMX_INDEXING_H264:
-		if ((pattern_type == DMX_FRM_H264_IDR_PIC) ||
-			(pattern_type == DMX_FRM_H264_NON_IDR_PIC))
+
+	case DMX_VIDEO_CODEC_H264:
+		if ((pattern_type == DMX_IDX_H264_IDR_START) ||
+			(pattern_type == DMX_IDX_H264_NON_IDR_START))
 			return 1;
 		return 0;
-	case DMX_INDEXING_VC1:
-		if (pattern_type == DMX_FRM_VC1_FRAME_START_CODE)
+
+	case DMX_VIDEO_CODEC_VC1:
+		if (pattern_type == DMX_IDX_VC1_FRAME_START)
 			return 1;
 		return 0;
+
 	default:
 		return -EINVAL;
 	}
 }
 
 /*
- * mpq_framing_pattern_lookup_results - framing lookup results
+ * mpq_dmx_get_pattern_params - Returns the required video
+ * patterns for framing operation based on video codec.
  *
- * @offset: The offset in the buffer where the pattern was found.
- * If a pattern is found using a prefix (i.e. started on the
- * previous buffer), offset is zero.
- * @type: the type of the pattern found.
- * @used_prefix_size: the prefix size that was used to find this pattern
- */
-struct mpq_framing_pattern_lookup_results {
-	struct {
-		u32 offset;
-		enum dmx_framing_pattern_type type;
-		u32 used_prefix_size;
-	} info[MPQ_MAX_FOUND_PATTERNS];
-};
-
-/*
- * Check if two patterns are identical, taking mask into consideration.
- * @pattern1: the first byte pattern to compare.
- * @pattern2: the second byte pattern to compare.
- * @mask: the bit mask to use.
- * @pattern_size: the length of both patterns and the mask, in bytes.
- *
- * Return: 1 if patterns match, 0 otherwise.
- */
-static inline int mpq_dmx_patterns_match(const u8 *pattern1, const u8 *pattern2,
-					const u8 *mask, size_t pattern_size)
-{
-	int i;
-
-	/*
-	 * Assumption: it is OK to access pattern1, pattern2 and mask.
-	 * This function performs no sanity checks to keep things fast.
-	 */
-
-	for (i = 0; i < pattern_size; i++)
-		if ((pattern1[i] & mask[i]) != (pattern2[i] & mask[i]))
-			return 0;
-
-	return 1;
-}
-
-/*
- * mpq_dmx_framing_pattern_search -
- * search for framing patterns in a given buffer.
- *
- * Optimized version: first search for a common substring, e.g. 0x00 0x00 0x01.
- * If this string is found, go over all the given patterns (all must start
- * with this string) and search for their ending in the buffer.
- *
- * Assumption: the patterns we look for do not spread over more than two
- * buffers.
- *
- * @paterns: the full patterns information to look for.
- * @patterns_num: the number of patterns to look for.
- * @buf: the buffer to search.
- * @buf_size: the size of the buffer to search. we search the entire buffer.
- * @prefix_size_masks: a bit mask (per pattern) of possible prefix sizes to use
- * when searching for a pattern that started at the last buffer.
- * Updated in this function for use in the next lookup.
- * @results: lookup results (offset, type, used_prefix_size) per found pattern,
- * up to MPQ_MAX_FOUND_PATTERNS.
- *
- * Return:
- *   Number of patterns found (up to MPQ_MAX_FOUND_PATTERNS).
- *   0 if pattern was not found.
- *   Negative error value on failure.
- */
-static int mpq_dmx_framing_pattern_search(
-		const struct mpq_framing_pattern_lookup_params *patterns,
-		int patterns_num,
-		const u8 *buf,
-		size_t buf_size,
-		struct mpq_framing_prefix_size_masks *prefix_size_masks,
-		struct mpq_framing_pattern_lookup_results *results)
-{
-	int i, j;
-	unsigned int current_size;
-	u32 prefix;
-	int found = 0;
-	int start_offset = 0;
-	/* the starting common substring to look for */
-	u8 string[] = {0x00, 0x00, 0x01};
-	/* the mask for the starting string */
-	u8 string_mask[] = {0xFF, 0xFF, 0xFF};
-	/* the size of the starting string (in bytes) */
-	size_t string_size = 3;
-
-	/* sanity checks - can be commented out for optimization purposes */
-	if ((patterns == NULL) || (patterns_num <= 0) || (buf == NULL)) {
-		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
-		return -EINVAL;
-	}
-
-	memset(results, 0, sizeof(struct mpq_framing_pattern_lookup_results));
-
-	/*
-	 * handle prefix - disregard string, simply check all patterns,
-	 * looking for a matching suffix at the very beginning of the buffer.
-	 */
-	for (j = 0; (j < patterns_num) && !found; j++) {
-		prefix = prefix_size_masks->size_mask[j];
-		current_size = 32;
-		while (prefix) {
-			if (prefix & (0x1 << (current_size - 1))) {
-				/*
-				 * check that we don't look further
-				 * than buf_size boundary
-				 */
-				if ((int)(patterns[j].size - current_size) >
-						buf_size)
-					break;
-
-				if (mpq_dmx_patterns_match(
-					(patterns[j].pattern + current_size),
-					buf, (patterns[j].mask + current_size),
-					(patterns[j].size - current_size))) {
-
-					MPQ_DVB_DBG_PRINT(
-						"%s: Found matching pattern using prefix of size %d\n",
-						__func__, current_size);
-					/*
-					 * pattern found using prefix at the
-					 * very beginning of the buffer, so
-					 * offset is 0, but we already zeroed
-					 * everything in the beginning of the
-					 * function. that's why the next line
-					 * is commented.
-					 */
-					/* results->info[found].offset = 0; */
-					results->info[found].type =
-							patterns[j].type;
-					results->info[found].used_prefix_size =
-							current_size;
-					found++;
-					/*
-					 * save offset to start looking from
-					 * in the buffer, to avoid reusing the
-					 * data of a pattern we already found.
-					 */
-					start_offset = (patterns[j].size -
-							current_size);
-
-					if (found >= MPQ_MAX_FOUND_PATTERNS)
-						goto next_prefix_lookup;
-					/*
-					 * we don't want to search for the same
-					 * pattern with several possible prefix
-					 * sizes if we have already found it,
-					 * so we break from the inner loop.
-					 * since we incremented 'found', we
-					 * will not search for additional
-					 * patterns using a prefix - that would
-					 * imply ambiguous patterns where one
-					 * pattern can be included in another.
-					 * the for loop will exit.
-					 */
-					break;
-				}
-			}
-			prefix &= ~(0x1 << (current_size - 1));
-			current_size--;
-		}
-	}
-
-	/*
-	 * Search buffer for entire pattern, starting with the string.
-	 * Note the external for loop does not execute if buf_size is
-	 * smaller than string_size (the cast to int is required, since
-	 * size_t is unsigned).
-	 */
-	for (i = start_offset; i < (int)(buf_size - string_size + 1); i++) {
-		if (mpq_dmx_patterns_match(string, (buf + i), string_mask,
-							string_size)) {
-			/* now search for patterns: */
-			for (j = 0; j < patterns_num; j++) {
-				/* avoid overflow to next buffer */
-				if ((i + patterns[j].size) > buf_size)
-					continue;
-
-				if (mpq_dmx_patterns_match(
-					(patterns[j].pattern + string_size),
-					(buf + i + string_size),
-					(patterns[j].mask + string_size),
-					(patterns[j].size - string_size))) {
-
-					results->info[found].offset = i;
-					results->info[found].type =
-						patterns[j].type;
-					/*
-					 * save offset to start next prefix
-					 * lookup, to avoid reusing the data
-					 * of any pattern we already found.
-					 */
-					if ((i + patterns[j].size) >
-							start_offset)
-						start_offset = (i +
-							patterns[j].size);
-					/*
-					 * did not use a prefix to find this
-					 * pattern, but we zeroed everything
-					 * in the beginning of the function.
-					 * So no need to zero used_prefix_size
-					 * for results->info[found]
-					 */
-
-					found++;
-					if (found >= MPQ_MAX_FOUND_PATTERNS)
-						goto next_prefix_lookup;
-					/*
-					 * theoretically we don't have to break
-					 * here, but we don't want to search
-					 * for the other matching patterns on
-					 * the very same same place in the
-					 * buffer. That would mean the
-					 * (pattern & mask) combinations are
-					 * not unique. So we break from inner
-					 * loop and move on to the next place
-					 * in the buffer.
-					 */
-					break;
-				}
-			}
-		}
-	}
-
-next_prefix_lookup:
-	/* check for possible prefix sizes for the next buffer */
-	for (j = 0; j < patterns_num; j++) {
-		prefix_size_masks->size_mask[j] = 0;
-		for (i = 1; i < patterns[j].size; i++) {
-			/*
-			 * avoid looking outside of the buffer
-			 * or reusing previously used data.
-			 */
-			if (i > (buf_size - start_offset))
-				break;
-
-			if (mpq_dmx_patterns_match(patterns[j].pattern,
-					(buf + buf_size - i),
-					patterns[j].mask, i)) {
-				prefix_size_masks->size_mask[j] |=
-						(1 << (i - 1));
-			}
-		}
-	}
-
-	return found;
-}
-
-/*
- * mpq_dmx_get_pattern_params -
- * get a pointer to the relevant pattern parameters structure,
- * based on the video parameters.
- *
- * @video_params: the video parameters (e.g. video standard).
- * @patterns: a pointer to a pointer to the pattern parameters,
- * updated by this function.
+ * @video_codec: the video codec.
+ * @patterns: a pointer to the pattern parameters, updated by this function.
  * @patterns_num: number of patterns, updated by this function.
  */
 static inline int mpq_dmx_get_pattern_params(
-		struct dmx_indexing_video_params *video_params,
-		const struct mpq_framing_pattern_lookup_params **patterns,
-		int *patterns_num)
+	enum dmx_video_codec video_codec,
+	const struct dvb_dmx_video_patterns
+		 *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM],
+	int *patterns_num)
 {
-	switch (video_params->standard) {
-	case DMX_INDEXING_MPEG2:
-		*patterns = mpeg2_patterns;
-		*patterns_num = MPQ_MPEG2_PATTERN_NUM;
+	switch (video_codec) {
+	case DMX_VIDEO_CODEC_MPEG2:
+		patterns[0] = dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER);
+		patterns[1] = dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP);
+		patterns[2] = dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START);
+		patterns[3] = dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START);
+		patterns[4] = dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START);
+		*patterns_num = 5;
 		break;
-	case DMX_INDEXING_H264:
-		*patterns = h264_patterns;
-		*patterns_num = MPQ_H264_PATTERN_NUM;
+
+	case DMX_VIDEO_CODEC_H264:
+		patterns[0] = dvb_dmx_get_pattern(DMX_IDX_H264_SPS);
+		patterns[1] = dvb_dmx_get_pattern(DMX_IDX_H264_PPS);
+		patterns[2] = dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START);
+		patterns[3] = dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START);
+		*patterns_num = 4;
 		break;
-	case DMX_INDEXING_VC1:
-		*patterns = vc1_patterns;
-		*patterns_num = MPQ_VC1_PATTERN_NUM;
+
+	case DMX_VIDEO_CODEC_VC1:
+		patterns[0] = dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER);
+		patterns[1] = dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT);
+		patterns[2] = dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START);
+		*patterns_num = 3;
 		break;
+
 	default:
 		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
-		*patterns = NULL;
 		*patterns_num = 0;
 		return -EINVAL;
 	}
@@ -1648,9 +1336,9 @@
 	/* get and store framing information if required */
 	if (!mpq_dmx_info.decoder_framing) {
 		mpq_dmx_get_pattern_params(
-			&mpq_feed->dvb_demux_feed->indexing_params,
-			&feed_data->patterns, &feed_data->patterns_num);
-		if (feed_data->patterns == NULL) {
+			mpq_feed->dvb_demux_feed->video_codec,
+			feed_data->patterns, &feed_data->patterns_num);
+		if (!feed_data->patterns_num) {
 			MPQ_DVB_ERR_PRINT(
 				"%s: FAILED to get framing pattern parameters\n",
 				__func__);
@@ -1740,10 +1428,10 @@
 		&feed_data->frame_offset);
 	feed_data->last_pattern_offset = 0;
 	feed_data->pending_pattern_len = 0;
-	feed_data->last_framing_match_type = DMX_FRM_UNKNOWN;
+	feed_data->last_framing_match_type = 0;
 	feed_data->found_sequence_header_pattern = 0;
 	memset(&feed_data->prefix_size, 0,
-			sizeof(struct mpq_framing_prefix_size_masks));
+			sizeof(struct dvb_dmx_video_prefix_size_masks));
 	feed_data->first_prefix_size = 0;
 	feed_data->saved_pts_dts_info.pts_exist = 0;
 	feed_data->saved_pts_dts_info.dts_exist = 0;
@@ -2613,7 +2301,7 @@
 
 	/* Report last pattern found */
 	if ((feed_data->pending_pattern_len) &&
-		mpq_dmx_is_video_frame(feed->indexing_params.standard,
+		mpq_dmx_is_video_frame(feed->video_codec,
 			feed_data->last_framing_match_type)) {
 		meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
 		mpq_dmx_write_pts_dts(feed_data,
@@ -2734,7 +2422,7 @@
 	struct mpq_demux *mpq_demux;
 	struct mpq_feed *mpq_feed;
 
-	struct mpq_framing_pattern_lookup_results framing_res;
+	struct dvb_dmx_video_patterns_results framing_res;
 	struct mpq_streambuffer_packet_header packet;
 	struct mpq_adapter_video_meta_data meta_data;
 	int bytes_written = 0;
@@ -2864,7 +2552,7 @@
 	 * the decoder requires demux to do framing,
 	 * so search for the patterns now.
 	 */
-	found_patterns = mpq_dmx_framing_pattern_search(
+	found_patterns = dvb_dmx_video_pattern_search(
 				feed_data->patterns,
 				feed_data->patterns_num,
 				(buf + ts_payload_offset),
@@ -2872,17 +2560,17 @@
 				&feed_data->prefix_size,
 				&framing_res);
 
-	if (!(feed_data->found_sequence_header_pattern)) {
+	if (!feed_data->found_sequence_header_pattern) {
 		for (i = 0; i < found_patterns; i++) {
 			if ((framing_res.info[i].type ==
-				DMX_FRM_MPEG2_SEQUENCE_HEADER) ||
+				DMX_IDX_MPEG_SEQ_HEADER) ||
 			    (framing_res.info[i].type ==
-				DMX_FRM_H264_SPS) ||
-			    (framing_res.info[i].type ==
-				DMX_FRM_VC1_SEQUENCE_HEADER)) {
+				DMX_IDX_H264_SPS) ||
+				(framing_res.info[i].type ==
+				DMX_IDX_VC1_SEQ_HEADER)) {
 
 				MPQ_DVB_DBG_PRINT(
-					"%s: Found Sequence Pattern, buf %p, i = %d, offset = %d, type = %d\n",
+					"%s: Found Sequence Pattern, buf %p, i = %d, offset = %d, type = %lld\n",
 					__func__, buf, i,
 					framing_res.info[i].offset,
 					framing_res.info[i].type);
@@ -2925,10 +2613,10 @@
 	if (feed_data->first_pts_dts_copy) {
 		for (i = first_pattern; i < found_patterns; i++) {
 			is_video_frame = mpq_dmx_is_video_frame(
-					feed->indexing_params.standard,
+					feed->video_codec,
 					framing_res.info[i].type);
 
-			if (is_video_frame) {
+			if (is_video_frame == 1) {
 				mpq_dmx_save_pts_dts(feed_data);
 				feed_data->first_pts_dts_copy = 0;
 				break;
@@ -2938,12 +2626,12 @@
 
 	/*
 	 * write prefix used to find first Sequence pattern, if needed.
-	 * feed_data->patterns[0].pattern always contains the Sequence
-	 * pattern.
+	 * feed_data->patterns[0]->pattern always contains the sequence
+	 * header pattern.
 	 */
 	if (feed_data->first_prefix_size) {
 		if (mpq_streambuffer_data_write(stream_buffer,
-					(feed_data->patterns[0].pattern),
+					(feed_data->patterns[0]->pattern),
 					feed_data->first_prefix_size) < 0) {
 			mpq_demux->decoder_drop_count +=
 				feed_data->first_prefix_size;
@@ -3045,9 +2733,8 @@
 		}
 
 		is_video_frame = mpq_dmx_is_video_frame(
-				feed->indexing_params.standard,
+				feed->video_codec,
 				feed_data->last_framing_match_type);
-
 		if (is_video_frame == 1) {
 			mpq_dmx_write_pts_dts(feed_data,
 				&(meta_data.info.framing.pts_dts_info));
@@ -3507,6 +3194,20 @@
 	return ret;
 }
 
+void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
+			const u8 timestamp[TIMESTAMP_LEN],
+			u64 *timestampIn27Mhz)
+{
+	if (unlikely(!timestampIn27Mhz))
+		return;
+
+	*timestampIn27Mhz = timestamp[2] << 16;
+	*timestampIn27Mhz += timestamp[1] << 8;
+	*timestampIn27Mhz += timestamp[0];
+	*timestampIn27Mhz *= 256; /* convert from 105.47 KHZ to 27MHz */
+}
+EXPORT_SYMBOL(mpq_dmx_convert_tts);
+
 int mpq_sdmx_open_session(struct mpq_demux *mpq_demux)
 {
 	enum sdmx_status ret = SDMX_SUCCESS;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
index 4c2a9f4..80b5428 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
@@ -31,8 +31,6 @@
  */
 #define TSIF_NAME_LENGTH				20
 
-#define MPQ_MAX_FOUND_PATTERNS				5
-
 /**
  * struct ts_packet_header - Transport packet header
  * as defined in MPEG2 transport stream standard.
@@ -200,17 +198,6 @@
 #endif
 } __packed;
 
-/*
- * mpq_framing_prefix_size_masks - possible prefix sizes.
- *
- * @size_mask: a bit mask (per pattern) of possible prefix sizes to use
- * when searching for a pattern that started in the last buffer.
- * Updated in mpq_dmx_framing_pattern_search for use in the next lookup
- */
-struct mpq_framing_prefix_size_masks {
-	u32 size_mask[MPQ_MAX_FOUND_PATTERNS];
-};
-
 /**
  * mpq_decoder_buffers_desc - decoder buffer(s) management information.
  *
@@ -295,14 +282,15 @@
 	u32 pes_header_offset;
 	int fullness_wait_cancel;
 	enum mpq_adapter_stream_if stream_interface;
-	const struct mpq_framing_pattern_lookup_params *patterns;
+	const struct dvb_dmx_video_patterns
+		*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
 	int patterns_num;
 	u32 frame_offset;
 	u32 last_pattern_offset;
 	u32 pending_pattern_len;
-	enum dmx_framing_pattern_type last_framing_match_type;
+	u64 last_framing_match_type;
 	int found_sequence_header_pattern;
-	struct mpq_framing_prefix_size_masks prefix_size;
+	struct dvb_dmx_video_prefix_size_masks prefix_size;
 	u32 first_prefix_size;
 	struct dmx_pts_dts_info saved_pts_dts_info;
 	struct dmx_pts_dts_info new_pts_dts_info;
@@ -651,6 +639,20 @@
 		struct dmx_secure_mode *secure_mode);
 
 /**
+ * mpq_dmx_convert_tts - Convert timestamp attached by HW to each TS
+ * packet to 27MHz.
+ *
+ * @feed: The feed with TTS attached
+ * @timestamp: Buffer holding the timestamp attached by the HW
+ * @timestampIn27Mhz: Timestamp result in 27MHz
+ *
+ * Return error code
+*/
+void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
+		const u8 timestamp[TIMESTAMP_LEN],
+		u64 *timestampIn27Mhz);
+
+/**
  * mpq_sdmx_open_session - Handle the details of opening a new secure demux
  * session for the specified mpq demux instance. Multiple calls to this
  * is allowed, reference counting is managed to open it only when needed.
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index 0d40520..8855e85 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -688,6 +688,7 @@
 	mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
 	mpq_demux->demux.set_secure_mode = NULL;
 	mpq_demux->demux.oob_command = mpq_dmx_oob_command;
+	mpq_demux->demux.convert_ts = mpq_dmx_convert_tts;
 
 	/* Initialize dvb_demux object */
 	result = dvb_dmx_init(&mpq_demux->demux);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index f0f8fa9..193141a 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1743,6 +1743,7 @@
 	mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
 	mpq_demux->demux.set_secure_mode = mpq_dmx_set_secure_mode;
 	mpq_demux->demux.oob_command = mpq_dmx_oob_command;
+	mpq_demux->demux.convert_ts = mpq_dmx_convert_tts;
 
 	/* Initialize dvb_demux object */
 	result = dvb_dmx_init(&mpq_demux->demux);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
index 81a2a93..c306488 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.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
@@ -128,6 +128,7 @@
 	mpq_demux->demux.reuse_decoder_buffer = NULL;
 	mpq_demux->demux.set_secure_mode = NULL;
 	mpq_demux->demux.oob_command = NULL;
+	mpq_demux->demux.convert_ts = NULL;
 
 	/* Initialize dvb_demux object */
 	result = dvb_dmx_init(&mpq_demux->demux);
diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
index b55f367..19abbbe 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_adapter.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
@@ -14,6 +14,7 @@
 #define _MPQ_ADAPTER_H
 
 #include "dvbdev.h"
+#include "dvb_demux.h"
 #include "mpq_stream_buffer.h"
 
 
@@ -36,31 +37,6 @@
 	MPQ_ADAPTER_MAX_NUM_OF_INTERFACES,
 };
 
-
-enum dmx_framing_pattern_type {
-	/* MPEG-2 */
-	DMX_FRM_MPEG2_SEQUENCE_HEADER,
-	DMX_FRM_MPEG2_GOP_HEADER,
-	DMX_FRM_MPEG2_I_PIC,
-	DMX_FRM_MPEG2_P_PIC,
-	DMX_FRM_MPEG2_B_PIC,
-	/* H.264 */
-	DMX_FRM_H264_SPS,
-	DMX_FRM_H264_PPS,
-	/* H.264 First Coded slice of an IDR Picture */
-	DMX_FRM_H264_IDR_PIC,
-	/* H.264 First Coded slice of a non-IDR Picture */
-	DMX_FRM_H264_NON_IDR_PIC,
-	/* VC-1 Sequence Header*/
-	DMX_FRM_VC1_SEQUENCE_HEADER,
-	/* VC-1 Entry Point Header (Advanced Profile only) */
-	DMX_FRM_VC1_ENTRY_POINT_HEADER,
-	/* VC-1 Frame Start Code */
-	DMX_FRM_VC1_FRAME_START_CODE,
-	/* Unknown or invalid framing information */
-	DMX_FRM_UNKNOWN
-};
-
 enum dmx_packet_type {
 	DMX_PES_PACKET,
 	DMX_FRAMING_INFO_PACKET,
@@ -83,8 +59,9 @@
 };
 
 struct dmx_framing_packet_info {
-	/** framing pattern type */
-	enum dmx_framing_pattern_type pattern_type;
+	/** framing pattern type, one of DMX_IDX_* definitions */
+	u64 pattern_type;
+
 	/** PTS/DTS information */
 	struct dmx_pts_dts_info pts_dts_info;
 };
diff --git a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
index 3f33535..0908a6e 100644
--- a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
+++ b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
@@ -131,24 +131,24 @@
 		switch (meta_data.packet_type) {
 		case DMX_FRAMING_INFO_PACKET:
 			switch (meta_data.info.framing.pattern_type) {
-			case DMX_FRM_H264_SPS:
-			case DMX_FRM_MPEG2_SEQUENCE_HEADER:
-			case DMX_FRM_VC1_SEQUENCE_HEADER:
+			case DMX_IDX_H264_SPS:
+			case DMX_IDX_MPEG_SEQ_HEADER:
+			case DMX_IDX_VC1_SEQ_HEADER:
 				DBG("SPS FOUND\n");
 				frame_found = false;
 				break;
-			case DMX_FRM_H264_PPS:
-			case DMX_FRM_MPEG2_GOP_HEADER:
-			case DMX_FRM_VC1_ENTRY_POINT_HEADER:
+			case DMX_IDX_H264_PPS:
+			case DMX_IDX_MPEG_GOP:
+			case DMX_IDX_VC1_ENTRY_POINT:
 				DBG("PPS FOUND\n");
 				frame_found = false;
 				break;
-			case DMX_FRM_H264_IDR_PIC:
-			case DMX_FRM_H264_NON_IDR_PIC:
-			case DMX_FRM_MPEG2_I_PIC:
-			case DMX_FRM_MPEG2_P_PIC:
-			case DMX_FRM_MPEG2_B_PIC:
-			case DMX_FRM_VC1_FRAME_START_CODE:
+			case DMX_IDX_H264_IDR_START:
+			case DMX_IDX_H264_NON_IDR_START:
+			case DMX_IDX_MPEG_I_FRAME_START:
+			case DMX_IDX_MPEG_P_FRAME_START:
+			case DMX_IDX_MPEG_B_FRAME_START:
+			case DMX_IDX_VC1_FRAME_START:
 				DBG("FRAME FOUND\n");
 				frame_found = true;
 				break;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index f46abcf..ef3e698 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1183,6 +1183,24 @@
 		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
 		break;
 	}
+	case HAL_PARAM_VENC_H264_VUI_TIMING_INFO:
+	{
+		struct hfi_h264_vui_timing_info *hfi;
+		struct hal_h264_vui_timing_info *timing_info = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO;
+
+		hfi = (struct hfi_h264_vui_timing_info *)&pkt->
+			rg_property_data[1];
+		hfi->enable = timing_info->enable;
+		hfi->fixed_frame_rate = timing_info->fixed_frame_rate;
+		hfi->time_scale = timing_info->time_scale;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_h264_vui_timing_info);
+		break;
+	}
 	case HAL_CONFIG_VPE_DEINTERLACE:
 		break;
 	/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
@@ -1213,6 +1231,7 @@
 	case HAL_PARAM_VENC_LOW_LATENCY:
 	default:
 		dprintk(VIDC_ERR, "DEFAULT: Calling 0x%x", ptype);
+		rc = -ENOTSUPP;
 		break;
 	}
 	return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index eca8091..f458a0a 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -241,7 +241,7 @@
 static u32 get_frame_size_compressed(int plane,
 					u32 height, u32 width)
 {
-	return (width * height * 3/2)/2;
+	return (width * height * 3/2)/4;
 }
 
 struct msm_vidc_format vdec_formats[] = {
@@ -1280,7 +1280,7 @@
 		break;
 	}
 
-	if (property_id) {
+	if (!rc && property_id) {
 		dprintk(VIDC_DBG,
 			"Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
 			property_id,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 160d450..da97c7a 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -131,7 +131,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_TIMING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
@@ -209,7 +209,8 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)
 		),
 		.qmenu = mpeg_video_rate_control,
-		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
+		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE |
+			MSM_VENC_CTRL_CLUSTER_TIMING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
@@ -630,6 +631,16 @@
 		.qmenu = mpeg_video_vidc_extradata,
 		.step = 0,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO,
+		.name = "H264 VUI Timing Info",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+		.cluster = MSM_VENC_CTRL_CLUSTER_TIMING,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1117,8 +1128,9 @@
 	struct hal_multi_slice_control multi_slice_control;
 	struct hal_h264_db_control h264_db_control;
 	struct hal_enable enable;
+	struct hal_h264_vui_timing_info vui_timing_info;
 	u32 property_id = 0, property_val = 0;
-	void *pdata;
+	void *pdata = NULL;
 	struct v4l2_ctrl *temp_ctrl = NULL;
 	struct hfi_device *hdev;
 
@@ -1625,14 +1637,57 @@
 		pdata = &extra;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+	{
+		struct v4l2_ctrl *rc_mode, *frame_rate;
+		bool cfr = false;
+
+		property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
+		rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+		frame_rate = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE);
+
+		switch (rc_mode->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+			cfr = true;
+			break;
+		default:
+			cfr = false;
+			break;
+		}
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED:
+			vui_timing_info.enable = 0;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
+			/* Only support this in CFR mode because we
+			 * don't really know how to fill out vui_timing_info.
+			 * time_scale in vfr mode.  The assumed framerate
+			 * might be incorrect. */
+			if (!cfr) {
+				dprintk(VIDC_ERR, "Can't set %x in VFR mode\n",
+						ctrl->id);
+				rc = -ENOTSUPP;
+				break;
+			}
+
+			vui_timing_info.enable = 1;
+			vui_timing_info.fixed_frame_rate = cfr;
+			vui_timing_info.time_scale = frame_rate->val;
+		}
+
+		pdata = &vui_timing_info;
+		break;
+	}
 	default:
 		rc = -ENOTSUPP;
 		break;
 	}
 #undef TRY_GET_CTRL
 
-	if (property_id) {
-		dprintk(VIDC_DBG, "Control: HAL property=%d,ctrl_value=%d\n",
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n",
 				property_id,
 				ctrl->val);
 		rc = call_hfi_op(hdev, session_set_property,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 3b82666..3729c3a 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -167,6 +167,7 @@
 	HAL_PARAM_VDEC_SYNC_FRAME_DECODE,
 	HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
 	HAL_CONFIG_VENC_MAX_BITRATE,
+	HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
 };
 
 enum hal_domain {
@@ -765,6 +766,13 @@
 	u32 time_stamp_scale;
 };
 
+
+struct hal_h264_vui_timing_info {
+	u32 enable;
+	u32 fixed_frame_rate;
+	u32 time_scale;
+};
+
 enum vidc_resource_id {
 	VIDC_RESOURCE_OCMEM = 0x00000001,
 	VIDC_UNUSED_RESORUCE = 0x10000000,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index baf7bc4..2d0c3bd 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -294,9 +294,16 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019)
 #define HFI_PROPERTY_PARAM_VENC_HIER_P_NUM_ENH_LAYER	\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01A)
-
 #define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT		\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B)
+#define HFI_PROPERTY_PARAM_VENC_H264_LTRMODE		\
+	 (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C)
+#define HFI_PROPERTY_PARAM_VENC_VIDEO_FULL_RANGE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
+#define HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
 
 #define HFI_PROPERTY_CONFIG_VENC_COMMON_START				\
 	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
@@ -500,6 +507,12 @@
 	u32 height;
 };
 
+struct hfi_h264_vui_timing_info {
+	u32 enable;
+	u32 fixed_frame_rate;
+	u32 time_scale;
+};
+
 #define HFI_COLOR_FORMAT_MONOCHROME			(HFI_COMMON_BASE + 0x1)
 #define HFI_COLOR_FORMAT_NV12				(HFI_COMMON_BASE + 0x2)
 #define HFI_COLOR_FORMAT_NV21				(HFI_COMMON_BASE + 0x3)
@@ -883,5 +896,4 @@
 	u32 packet_type;
 	u32 trigger_type;
 };
-
 #endif
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index b719b3f..4f7fb44 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -28,6 +28,7 @@
 #define BUF_TYPE_INPUT V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
 
 static struct ion_client *venc_ion_client;
+static long venc_secure(struct v4l2_subdev *sd);
 
 struct index_bitmap {
 	unsigned long *bitmap;
@@ -321,8 +322,9 @@
 		goto venc_open_fail;
 	}
 
-	inst->secure = false;
 	inst->vmops = *vmops;
+	inst->secure = vmops->secure; /* We need to inform vidc, but defer
+					 until after s_fmt() */
 	INIT_LIST_HEAD(&inst->registered_output_bufs.list);
 	INIT_LIST_HEAD(&inst->registered_input_bufs.list);
 	init_completion(&inst->dq_complete);
@@ -903,6 +905,15 @@
 		WFD_MSG_ERR("Failed to format for input port\n");
 		goto venc_set_format_fail;
 	}
+
+	/* If the device was secured previously, we need to inform vidc _now_ */
+	if (inst->secure) {
+		rc = venc_secure(sd);
+		if (rc) {
+			WFD_MSG_ERR("Failed secure vidc\n");
+			goto venc_set_format_fail;
+		}
+	}
 venc_set_format_fail:
 	return rc;
 }
@@ -1329,12 +1340,6 @@
 		rc = -EEXIST;
 	}
 
-	if (inst->secure) {
-		/* Nothing to do! */
-		rc = 0;
-		goto secure_fail;
-	}
-
 	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE;
 	rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
 	if (rc) {
@@ -1342,7 +1347,6 @@
 		goto secure_fail;
 	}
 
-	inst->secure = true;
 secure_fail:
 	return rc;
 }
@@ -1419,9 +1423,6 @@
 	case SET_FRAMERATE_MODE:
 		rc = venc_set_framerate_mode(sd, arg);
 		break;
-	case ENC_SECURE:
-		rc = venc_secure(sd);
-		break;
 	default:
 		WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
 		rc = -ENOTSUPP;
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 16de0d4..55386b9 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -26,6 +26,8 @@
 	struct switch_dev sdev;
 };
 
+static int mdp_secure(struct v4l2_subdev *sd, void *arg);
+
 int mdp_init(struct v4l2_subdev *sd, u32 val)
 {
 	return 0;
@@ -47,10 +49,6 @@
 		WFD_MSG_ERR("Invalid arguments\n");
 		rc = -EINVAL;
 		goto mdp_open_fail;
-	} else if (mops->secure) {
-		/* Deprecated API; use MDP_SECURE ioctl */
-		WFD_MSG_ERR("Deprecated API for securing subdevice\n");
-		return -ENOTSUPP;
 	}
 
 	fbi = msm_fb_get_writeback_fb();
@@ -66,12 +64,25 @@
 		WFD_MSG_ERR("WFD switch registration failed\n");
 		goto mdp_open_fail;
 	}
+
 	msm_fb_writeback_init(fbi);
+
 	inst->mdp = fbi;
 	inst->secure = mops->secure;
+	if (mops->secure) {
+		rc = mdp_secure(sd, inst);
+		if (rc) {
+			WFD_MSG_ERR("Couldn't secure MDP\n");
+			goto mdp_secure_fail;
+		}
+	}
+
 
 	mops->cookie = inst;
-	return rc;
+	return 0;
+mdp_secure_fail:
+	switch_dev_unregister(&inst->sdev);
+	msm_fb_writeback_terminate(inst->mdp);
 mdp_open_fail:
 	kfree(inst);
 	return rc;
@@ -118,7 +129,8 @@
 	}
 	return 0;
 }
-int mdp_close(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_close(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_instance *inst = arg;
 	struct fb_info *fbi = NULL;
@@ -133,7 +145,8 @@
 	}
 	return 0;
 }
-int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	int rc = 0;
 	struct mdp_buf_info *binfo = arg;
@@ -161,7 +174,8 @@
 		WFD_MSG_ERR("Failed to queue buffer\n");
 	return rc;
 }
-int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	int rc = 0;
 	struct mdp_buf_info *obuf = arg;
@@ -184,7 +198,8 @@
 	obuf->cookie = (void *)fbdata.priv;
 	return rc;
 }
-int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_prop *prop = (struct mdp_prop *)arg;
 	struct mdp_instance *inst = prop->inst;
@@ -197,7 +212,7 @@
 	return 0;
 }
 
-int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+static int mdp_mmap(struct v4l2_subdev *sd, void *arg)
 {
 	int rc = 0, align = 0;
 	struct mem_region_map *mmap = arg;
@@ -250,7 +265,7 @@
 	return rc;
 }
 
-int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+static int mdp_munmap(struct v4l2_subdev *sd, void *arg)
 {
 	struct mem_region_map *mmap = arg;
 	struct mem_region *mregion;
@@ -278,7 +293,7 @@
 	return 0;
 }
 
-int mdp_secure(struct v4l2_subdev *sd, void *arg)
+static int mdp_secure(struct v4l2_subdev *sd, void *arg)
 {
 	struct mdp_instance *inst = NULL;
 	int rc = 0;
@@ -331,9 +346,6 @@
 	case MDP_MUNMAP:
 		rc = mdp_munmap(sd, arg);
 		break;
-	case MDP_SECURE:
-		rc = mdp_secure(sd, arg);
-		break;
 	default:
 		WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
 		rc = -EINVAL;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 1d3c9f55..af3cd69 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -1040,30 +1040,9 @@
 {
 	int rc = 0;
 	struct wfd_device *wfd_dev = video_drvdata(filp);
-	struct wfd_inst *inst = file_to_inst(filp);
 
-	switch (a->id) {
-	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
-		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
-				ioctl, ENC_SECURE, NULL);
-		if (rc) {
-			WFD_MSG_ERR("Couldn't secure encoder");
-			break;
-		}
-
-		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
-				ioctl, MDP_SECURE, (void *)inst->mdp_inst);
-		if (rc) {
-			WFD_MSG_ERR("Couldn't secure MDP");
-			break;
-		}
-
-		wfd_dev->secure = true;
-		break;
-	default:
-		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
-				ioctl, SET_PROP, a);
-	}
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+			ioctl, SET_PROP, a);
 
 	if (rc)
 		WFD_MSG_ERR("Failed to set encoder property\n");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 188ac32..c02eecf 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -157,8 +157,6 @@
 	uint32_t user_virt_sb_base;
 	size_t sb_length;
 	struct ion_handle *ihandle;		/* Retrieve phy addr */
-	bool  perf_enabled;
-	bool  fast_load_enabled;
 };
 
 struct qseecom_listener_handle {
@@ -177,6 +175,8 @@
 	int               abort;
 	wait_queue_head_t abort_wq;
 	atomic_t          ioctl_count;
+	bool  perf_enabled;
+	bool  fast_load_enabled;
 };
 
 enum qseecom_set_clear_key_flag {
@@ -1789,9 +1789,9 @@
 		pr_err("Unable to find the handle, exiting\n");
 	else
 		ret = qseecom_unload_app(data);
-	if (data->client.fast_load_enabled == true)
+	if (data->fast_load_enabled == true)
 		qsee_disable_clock_vote(data, CLK_SFPB);
-	if (data->client.perf_enabled == true)
+	if (data->perf_enabled == true)
 		qsee_disable_clock_vote(data, CLK_DFAB);
 	if (ret == 0) {
 		kzfree(data);
@@ -1972,11 +1972,11 @@
 								ret);
 			else {
 				qseecom.qsee_bw_count++;
-				data->client.perf_enabled = true;
+				data->perf_enabled = true;
 			}
 		} else {
 			qseecom.qsee_bw_count++;
-			data->client.perf_enabled = true;
+			data->perf_enabled = true;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -2004,11 +2004,11 @@
 								ret);
 			else {
 				qseecom.qsee_sfpb_bw_count++;
-				data->client.fast_load_enabled = true;
+				data->fast_load_enabled = true;
 			}
 		} else {
 			qseecom.qsee_sfpb_bw_count++;
-			data->client.fast_load_enabled = true;
+			data->fast_load_enabled = true;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -2053,11 +2053,11 @@
 								ret);
 			else {
 				qseecom.qsee_bw_count--;
-				data->client.perf_enabled = false;
+				data->perf_enabled = false;
 			}
 		} else {
 			qseecom.qsee_bw_count--;
-			data->client.perf_enabled = false;
+			data->perf_enabled = false;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -2083,11 +2083,11 @@
 								ret);
 			else {
 				qseecom.qsee_sfpb_bw_count--;
-				data->client.fast_load_enabled = false;
+				data->fast_load_enabled = false;
 			}
 		} else {
 			qseecom.qsee_sfpb_bw_count--;
-			data->client.fast_load_enabled = false;
+			data->fast_load_enabled = false;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -2853,9 +2853,9 @@
 		}
 	}
 
-	if (data->client.fast_load_enabled == true)
+	if (data->fast_load_enabled == true)
 		qsee_disable_clock_vote(data, CLK_SFPB);
-	if (data->client.perf_enabled == true)
+	if (data->perf_enabled == true)
 		qsee_disable_clock_vote(data, CLK_DFAB);
 
 	if (qseecom.qseos_version == QSEOS_VERSION_13) {
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index b075435..5b7f08f 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -646,6 +646,7 @@
 
 	mrq.cmd = &cmd;
 
+	mmc_rpm_hold(card->host, &card->dev);
 	mmc_claim_host(card->host);
 
 	err = mmc_blk_part_switch(card, md);
@@ -695,6 +696,7 @@
 
 cmd_rel_host:
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 
 cmd_done:
 	mmc_blk_put(md);
@@ -775,6 +777,7 @@
 		goto idata_free;
 	}
 
+	mmc_rpm_hold(card->host, &card->dev);
 	mmc_claim_host(card->host);
 
 	err = mmc_blk_part_switch(card, md);
@@ -871,6 +874,7 @@
 
 cmd_rel_host:
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 
 idata_free:
 	for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d339d81..73a1b41 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -167,10 +167,12 @@
 
 static inline void mmc_update_clk_scaling(struct mmc_host *host)
 {
-	if (host->clk_scaling.enable)
+	if (host->clk_scaling.enable) {
 		host->clk_scaling.busy_time_us +=
 			ktime_to_us(ktime_sub(ktime_get(),
 					host->clk_scaling.start_busy));
+		host->clk_scaling.start_busy = ktime_get();
+	}
 }
 /**
  *	mmc_request_done - finish processing an MMC request
@@ -811,6 +813,12 @@
 			context_info->is_urgent = false;
 			context_info->is_new_req = false;
 			if (mmc_should_stop_curr_req(host)) {
+				/*
+				 * We are going to stop the ongoing request.
+				 * Update stuff that we ought to do when the
+				 * request actually completes.
+				 */
+				mmc_update_clk_scaling(host);
 				err = mmc_stop_request(host);
 				if (err && !context_info->is_done_rcv) {
 					err = MMC_BLK_ABORT;
@@ -823,14 +831,6 @@
 					context_info->is_done_rcv = false;
 					break; /* return err */
 				} else {
-					/*
-					 * We have stopped the ongoing request
-					 * and are sure that mmc_request_done()
-					 * is not going to get called. Update
-					 * stuff that we ought to do when the
-					 * request actually completes.
-					 */
-					mmc_update_clk_scaling(host);
 					mmc_host_clk_release(host);
 				}
 				err = host->areq->update_interrupted_req(
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2038d3d..6b392b9 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2416,6 +2416,9 @@
 		goto out;
 	}
 
+	if (msm_host->msm_bus_vote.client_handle)
+		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+
 	return sdhci_msm_runtime_suspend(dev);
 out:
 	return ret;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d58379f..904c255 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1094,6 +1094,8 @@
 	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
 		flags |= SDHCI_CMD_DATA;
 
+	if (cmd->data)
+		host->data_start_time = ktime_get();
 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 }
 
@@ -2361,7 +2363,6 @@
 		sdhci_finish_command(host);
 }
 
-#ifdef CONFIG_MMC_DEBUG
 static void sdhci_show_adma_error(struct sdhci_host *host)
 {
 	const char *name = mmc_hostname(host->mmc);
@@ -2377,7 +2378,7 @@
 		len = (__le16 *)(desc + 2);
 		attr = *desc;
 
-		DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+		pr_info("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
 		    name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr);
 
 		desc += 8;
@@ -2386,9 +2387,6 @@
 			break;
 	}
 }
-#else
-static void sdhci_show_adma_error(struct sdhci_host *host) { }
-#endif
 
 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 {
@@ -2453,9 +2451,10 @@
 			pr_msg = true;
 		}
 		if (pr_msg) {
-			pr_err("%s: data txfr (0x%08x) error: %d\n",
+			pr_err("%s: data txfr (0x%08x) error: %d after %lld ms\n",
 			       mmc_hostname(host->mmc), intmask,
-			       host->data->error);
+			       host->data->error, ktime_to_ms(ktime_sub(
+			       ktime_get(), host->data_start_time)));
 			sdhci_dumpregs(host);
 		}
 		sdhci_finish_data(host);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 0158235..44465dc 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -91,9 +91,6 @@
 #define CCU_PRONTO_LAST_ADDR1_OFFSET		0x10
 #define CCU_PRONTO_LAST_ADDR2_OFFSET		0x14
 
-#define MSM_PRONTO_CCPU_CTL_BASE	0xfb21d000
-#define BOOT_REMAP_OFFSET		0x04
-
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		500
 #define WCNSS_VERSION_LEN			30
@@ -200,7 +197,6 @@
 	void __iomem *riva_ccu_base;
 	void __iomem *pronto_a2xb_base;
 	void __iomem *pronto_ccpu_base;
-	void __iomem *pronto_ctl_base;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -334,10 +330,6 @@
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
 
-	reg_addr = penv->pronto_ctl_base + BOOT_REMAP_OFFSET;
-	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: BOOT_REMAP_ADDR %08x\n", __func__, reg);
-
 	tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
 	tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
 
@@ -1191,20 +1183,11 @@
 			pr_err("%s: ioremap wcnss physical failed\n", __func__);
 			goto fail_ioremap2;
 		}
-		penv->pronto_ctl_base = ioremap(MSM_PRONTO_CCPU_CTL_BASE,
-						SZ_32);
-		if (!penv->pronto_ctl_base) {
-			ret = -ENOMEM;
-			pr_err("%s: ioremap wcnss physical failed\n", __func__);
-			goto fail_ioremap3;
-		}
 	}
 	penv->cold_boot_done = 1;
 
 	return 0;
 
-fail_ioremap3:
-	iounmap(penv->pronto_ccpu_base);
 fail_ioremap2:
 	iounmap(penv->pronto_a2xb_base);
 fail_ioremap:
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 1729b49..52c523e 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.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
@@ -463,7 +463,7 @@
 	int			i, pwm_size, rc = 0;
 	int			burst_size = SPMI_MAX_BUF_LEN;
 	int			list_len = lut->list_len << 1;
-	int			offset = lut->lo_index << 1;
+	int			offset = (lut->lo_index << 1) - 2;
 
 	pwm_size = QPNP_GET_PWM_SIZE(
 			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
@@ -1024,8 +1024,8 @@
 		raw_lut = 1;
 
 	lut_config->list_len = len;
-	lut_config->lo_index = start_idx;
-	lut_config->hi_index = start_idx + len - 1;
+	lut_config->lo_index = start_idx + 1;
+	lut_config->hi_index = start_idx + len;
 
 	rc = qpnp_lpg_change_table(pwm, duty_pct, raw_lut);
 	if (rc) {
@@ -1041,13 +1041,13 @@
 
 	QPNP_SET_PAUSE_CNT(lut_config->lut_pause_lo_cnt,
 			lut_params.lut_pause_lo, ramp_step_ms);
-	if (lut_config->lut_pause_lo_cnt > PM_PWM_LUT_PAUSE_MAX)
-		lut_config->lut_pause_lo_cnt = PM_PWM_LUT_PAUSE_MAX;
+	if (lut_config->lut_pause_lo_cnt > PM_PWM_MAX_PAUSE_CNT)
+		lut_config->lut_pause_lo_cnt = PM_PWM_MAX_PAUSE_CNT;
 
 	QPNP_SET_PAUSE_CNT(lut_config->lut_pause_hi_cnt,
 			lut_params.lut_pause_hi, ramp_step_ms);
-	if (lut_config->lut_pause_hi_cnt > PM_PWM_LUT_PAUSE_MAX)
-			lut_config->lut_pause_hi_cnt = PM_PWM_LUT_PAUSE_MAX;
+	if (lut_config->lut_pause_hi_cnt > PM_PWM_MAX_PAUSE_CNT)
+			lut_config->lut_pause_hi_cnt = PM_PWM_MAX_PAUSE_CNT;
 
 	lut_config->ramp_step_ms = ramp_step_ms;
 
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 47108c6..6412fc0 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -886,6 +886,12 @@
 				(u32) base, status);
 			bam_output_register_content(base);
 			*cb_case = SPS_CALLBACK_BAM_HRESP_ERR_IRQ;
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		} else if (status & IRQ_STTS_BAM_TIMER_IRQ) {
+			SPS_DBG1("sps:bam 0x%x(va);receive BAM_TIMER_IRQ\n",
+				(u32) base);
+			*cb_case = SPS_CALLBACK_BAM_TIMER_IRQ;
+#endif
 		} else
 			SPS_INFO("sps:bam 0x%x(va);bam irq status="
 				"0x%x.", (u32) base, status);
@@ -1126,9 +1132,25 @@
 void bam_pipe_timer_config(void *base, u32 pipe, enum bam_pipe_timer_mode mode,
 			 u32 timeout_count)
 {
-	bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_MODE, mode);
-	bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_TRSHLD,
-			    timeout_count);
+	u32 for_all_pipes = 0;
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	for_all_pipes = bam_read_reg_field(base, REVISION,
+						BAM_NUM_INACTIV_TMRS);
+#endif
+
+	if (for_all_pipes) {
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		bam_write_reg_field(base, TIMER_CTRL, TIMER_MODE, mode);
+		bam_write_reg_field(base, TIMER_CTRL, TIMER_TRSHLD,
+				    timeout_count);
+#endif
+	} else {
+		bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_MODE,
+					mode);
+		bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_TRSHLD,
+				    timeout_count);
+	}
 }
 
 /**
@@ -1137,10 +1159,26 @@
  */
 void bam_pipe_timer_reset(void *base, u32 pipe)
 {
-	/* reset */
-	bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_RST, 0);
-	/* active */
-	bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_RST, 1);
+	u32 for_all_pipes = 0;
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	for_all_pipes = bam_read_reg_field(base, REVISION,
+						BAM_NUM_INACTIV_TMRS);
+#endif
+
+	if (for_all_pipes) {
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		/* reset */
+		bam_write_reg_field(base, TIMER_CTRL, TIMER_RST, 0);
+		/* active */
+		bam_write_reg_field(base, TIMER_CTRL, TIMER_RST, 1);
+#endif
+	} else {
+		/* reset */
+		bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_RST, 0);
+		/* active */
+		bam_write_reg_field(base, P_TIMER_CTRL(pipe), P_TIMER_RST, 1);
+	}
 }
 
 /**
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index cda1717..23c346a 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -2232,8 +2232,7 @@
 		SPS_ERR("sps:%s:timer_ctrl pointer is NULL.\n", __func__);
 		return SPS_ERROR;
 	} else if (timer_result == NULL) {
-		SPS_ERR("sps:%s:result pointer is NULL.\n", __func__);
-		return SPS_ERROR;
+		SPS_DBG("sps:%s:no result to return.\n", __func__);
 	}
 
 	bam = sps_bam_lock(pipe);
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index a84d99e..80056f5 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -24,7 +24,8 @@
 #include "spsi.h"
 
 /* All BAM global IRQ sources */
-#define BAM_IRQ_ALL (BAM_DEV_IRQ_HRESP_ERROR | BAM_DEV_IRQ_ERROR)
+#define BAM_IRQ_ALL (BAM_DEV_IRQ_HRESP_ERROR | BAM_DEV_IRQ_ERROR |   \
+	BAM_DEV_IRQ_TIMER)
 
 /* BAM device state flags */
 #define BAM_STATE_INIT     (1UL << 1)
@@ -145,7 +146,7 @@
 				BAM_ID(dev), source, mask);
 
 		if ((source & (1UL << 31)) && (dev->props.callback)) {
-			SPS_INFO("sps:bam_isr:bam=0x%x;callback for case %d.\n",
+			SPS_DBG1("sps:bam_isr:bam=0x%x;callback for case %d.\n",
 				BAM_ID(dev), cb_case);
 			dev->props.callback(cb_case, dev->props.user);
 		}
@@ -2027,7 +2028,7 @@
 			BAM_PIPE_TIMER_ONESHOT :
 			BAM_PIPE_TIMER_PERIODIC;
 		bam_pipe_timer_config(dev->base, pipe_index, mode,
-				    timer_ctrl->timeout_msec * 10);
+				    timer_ctrl->timeout_msec * 8);
 		break;
 	case SPS_TIMER_OP_RESET:
 		bam_pipe_timer_reset(dev->base, pipe_index);
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index bbc0373..dede487 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
 	BAM_DEV_IRQ_RDY_TO_SLEEP = 0x00000001,
 	BAM_DEV_IRQ_HRESP_ERROR = 0x00000002,
 	BAM_DEV_IRQ_ERROR = 0x00000004,
+	BAM_DEV_IRQ_TIMER = 0x00000010,
 };
 
 /* Pipe interrupt mask */
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index ee80975..9ba954a 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -1504,11 +1504,10 @@
 	},
 };
 
-static int __init tsens_tm_init_driver(void)
+int __init tsens_tm_init_driver(void)
 {
 	return platform_driver_register(&tsens_tm_driver);
 }
-arch_initcall(tsens_tm_init_driver);
 
 static int __init tsens_thermal_register(void)
 {
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 5aca48d..12ac3bc 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -23,17 +23,447 @@
 #include <linux/msm_thermal.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
 #include <mach/cpufreq.h>
+#include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
+#include <linux/regulator/consumer.h>
 
-static int enabled;
+#define MAX_RAILS 5
+
 static struct msm_thermal_data msm_thermal_info;
 static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
 static struct delayed_work check_temp_work;
+static bool core_control_enabled;
+static uint32_t cpus_offlined;
+static DEFINE_MUTEX(core_control_mutex);
 
+static int enabled;
+static int rails_cnt;
+static int psm_rails_cnt;
 static int limit_idx;
 static int limit_idx_low;
 static int limit_idx_high;
+static int max_tsens_num;
 static struct cpufreq_frequency_table *table;
+static uint32_t usefreq;
+static int freq_table_get;
+static bool vdd_rstr_enabled;
+static bool vdd_rstr_nodes_called;
+static bool vdd_rstr_probed;
+static bool psm_enabled;
+static bool psm_nodes_called;
+static bool psm_probed;
+static DEFINE_MUTEX(vdd_rstr_mutex);
+static DEFINE_MUTEX(psm_mutex);
+
+struct rail {
+	const char *name;
+	uint32_t freq_req;
+	uint32_t min_level;
+	uint32_t num_levels;
+	uint32_t curr_level;
+	uint32_t levels[3];
+	struct kobj_attribute value_attr;
+	struct kobj_attribute level_attr;
+	struct regulator *reg;
+	struct attribute_group attr_gp;
+};
+
+struct psm_rail {
+	const char *name;
+	uint8_t init;
+	uint8_t mode;
+	struct kobj_attribute mode_attr;
+	struct rpm_regulator *reg;
+	struct attribute_group attr_gp;
+};
+
+static struct psm_rail *psm_rails;
+static struct rail *rails;
+
+struct vdd_rstr_enable {
+	struct kobj_attribute ko_attr;
+	uint32_t enabled;
+};
+
+/* For SMPS only*/
+enum PMIC_SW_MODE {
+	PMIC_AUTO_MODE  = RPM_REGULATOR_MODE_AUTO,
+	PMIC_IPEAK_MODE = RPM_REGULATOR_MODE_IPEAK,
+	PMIC_PWM_MODE   = RPM_REGULATOR_MODE_HPM,
+};
+
+#define VDD_RES_RO_ATTRIB(_rail, ko_attr, j, _name) \
+	ko_attr.attr.name = __stringify(_name); \
+	ko_attr.attr.mode = 444; \
+	ko_attr.show = vdd_rstr_reg_##_name##_show; \
+	ko_attr.store = NULL; \
+	_rail.attr_gp.attrs[j] = &ko_attr.attr;
+
+#define VDD_RES_RW_ATTRIB(_rail, ko_attr, j, _name) \
+	ko_attr.attr.name = __stringify(_name); \
+	ko_attr.attr.mode = 644; \
+	ko_attr.show = vdd_rstr_reg_##_name##_show; \
+	ko_attr.store = vdd_rstr_reg_##_name##_store; \
+	_rail.attr_gp.attrs[j] = &ko_attr.attr;
+
+#define VDD_RSTR_ENABLE_FROM_ATTRIBS(attr) \
+	(container_of(attr, struct vdd_rstr_enable, ko_attr));
+
+#define VDD_RSTR_REG_VALUE_FROM_ATTRIBS(attr) \
+	(container_of(attr, struct rail, value_attr));
+
+#define VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr) \
+	(container_of(attr, struct rail, level_attr));
+
+#define PSM_RW_ATTRIB(_rail, ko_attr, j, _name) \
+	ko_attr.attr.name = __stringify(_name); \
+	ko_attr.attr.mode = 644; \
+	ko_attr.show = psm_reg_##_name##_show; \
+	ko_attr.store = psm_reg_##_name##_store; \
+	_rail.attr_gp.attrs[j] = &ko_attr.attr;
+
+#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
+	(container_of(attr, struct psm_rail, mode_attr));
+/* If freq table exists, then we can send freq request */
+static int check_freq_table(void)
+{
+	int ret = 0;
+	struct cpufreq_frequency_table *table = NULL;
+
+	table = cpufreq_frequency_get_table(0);
+	if (!table) {
+		pr_debug("%s: error reading cpufreq table\n", __func__);
+		return -EINVAL;
+	}
+	freq_table_get = 1;
+
+	return ret;
+}
+
+static int update_cpu_min_freq_all(uint32_t min)
+{
+	int cpu = 0;
+	int ret = 0;
+
+	if (!freq_table_get) {
+		ret = check_freq_table();
+		if (ret) {
+			pr_err("%s:Fail to get freq table\n", __func__);
+			return ret;
+		}
+	}
+	/* If min is larger than allowed max */
+	if (min != MSM_CPUFREQ_NO_LIMIT &&
+			min > table[limit_idx_high].frequency)
+		min = table[limit_idx_high].frequency;
+
+	for_each_possible_cpu(cpu) {
+		ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
+
+		if (ret) {
+			pr_err("%s:Fail to set limits for cpu%d\n",
+					__func__, cpu);
+			return ret;
+		}
+
+		if (cpufreq_update_policy(cpu))
+			pr_debug("%s: Cannot update policy for cpu%d\n",
+					__func__, cpu);
+	}
+
+	return ret;
+}
+
+static int vdd_restriction_apply_freq(struct rail *r, int level)
+{
+	int ret = 0;
+
+	/* level = -1: disable, level = 0,1,2..n: enable */
+	if (level == -1) {
+		ret = update_cpu_min_freq_all(r->min_level);
+		if (ret)
+			return ret;
+		else
+			r->curr_level = -1;
+	} else if (level >= 0 && level < (r->num_levels)) {
+		ret = update_cpu_min_freq_all(r->levels[level]);
+		if (ret)
+			return ret;
+		else
+			r->curr_level = level;
+	} else {
+		pr_err("level input:%d is not within range\n", level);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int vdd_restriction_apply_voltage(struct rail *r, int level)
+{
+	int ret = 0;
+
+	if (r->reg == NULL) {
+		pr_info("Do not have regulator handle:%s, can't apply vdd\n",
+				r->name);
+		return -EFAULT;
+	}
+	/* level = -1: disable, level = 0,1,2..n: enable */
+	if (level == -1) {
+		ret = regulator_set_voltage(r->reg, r->min_level,
+			r->levels[r->num_levels - 1]);
+		if (!ret)
+			r->curr_level = -1;
+	} else if (level >= 0 && level < (r->num_levels)) {
+		ret = regulator_set_voltage(r->reg, r->levels[level],
+			r->levels[r->num_levels - 1]);
+		if (!ret)
+			r->curr_level = level;
+	} else {
+		pr_err("level input:%d is not within range\n", level);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+/* 1:enable, 0:disable */
+static int vdd_restriction_apply_all(int en)
+{
+	int i = 0;
+	int fail_cnt = 0;
+	int ret = 0;
+
+	for (i = 0; i < rails_cnt; i++) {
+		if (rails[i].freq_req == 1 && freq_table_get)
+			ret = vdd_restriction_apply_freq(&rails[i],
+					en ? 0 : -1);
+		else
+			ret = vdd_restriction_apply_voltage(&rails[i],
+					en ? 0 : -1);
+		if (ret) {
+			pr_err("Cannot set voltage for %s", rails[i].name);
+			fail_cnt++;
+		}
+	}
+	/* Check fail_cnt again to make sure all of the rails are applied
+	 * restriction successfully or not */
+	if (fail_cnt)
+		return -EFAULT;
+
+	return ret;
+}
+
+/* Setting all rails the same mode */
+static int psm_set_mode_all(int mode)
+{
+	int i = 0;
+	int fail_cnt = 0;
+	int ret = 0;
+
+	for (i = 0; i < psm_rails_cnt; i++) {
+		if (psm_rails[i].mode != mode) {
+			ret = rpm_regulator_set_mode(psm_rails[i].reg, mode);
+			if (ret) {
+				pr_err("Cannot set mode:%d for %s",
+					mode, psm_rails[i].name);
+				fail_cnt++;
+			} else
+				psm_rails[i].mode = mode;
+		}
+	}
+
+	return fail_cnt ? (-EFAULT) : ret;
+}
+
+static int vdd_rstr_en_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct vdd_rstr_enable *en = VDD_RSTR_ENABLE_FROM_ATTRIBS(attr);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", en->enabled);
+}
+
+static ssize_t vdd_rstr_en_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	int i = 0;
+	uint8_t en_cnt = 0;
+	uint8_t dis_cnt = 0;
+	uint32_t val = 0;
+	struct kernel_param kp;
+	struct vdd_rstr_enable *en = VDD_RSTR_ENABLE_FROM_ATTRIBS(attr);
+
+	mutex_lock(&vdd_rstr_mutex);
+	kp.arg = &val;
+	ret = param_set_bool(buf, &kp);
+	if (ret) {
+		pr_err("Invalid input %s for enabled\n", buf);
+		goto done_vdd_rstr_en;
+	}
+
+	if ((val == 0) && (en->enabled == 0))
+		goto done_vdd_rstr_en;
+
+	for (i = 0; i < rails_cnt; i++) {
+		if (rails[i].freq_req == 1 && freq_table_get)
+			ret = vdd_restriction_apply_freq(&rails[i],
+					(val) ? 0 : -1);
+		else
+			ret = vdd_restriction_apply_voltage(&rails[i],
+			(val) ? 0 : -1);
+
+		/* Even if fail to set one rail, still try to set the
+		 * others. Continue the loop */
+		if (ret)
+			pr_err("Set vdd restriction for %s failed\n",
+					rails[i].name);
+		else {
+			if (val)
+				en_cnt++;
+			else
+				dis_cnt++;
+		}
+	}
+	/* As long as one rail is enabled, vdd rstr is enabled */
+	if (val && en_cnt)
+		en->enabled = 1;
+	else if (!val && (dis_cnt == rails_cnt))
+		en->enabled = 0;
+
+done_vdd_rstr_en:
+	mutex_unlock(&vdd_rstr_mutex);
+	return count;
+}
+
+static struct vdd_rstr_enable vdd_rstr_en = {
+	.ko_attr.attr.name = __stringify(enabled),
+	.ko_attr.attr.mode = 644,
+	.ko_attr.show = vdd_rstr_en_show,
+	.ko_attr.store = vdd_rstr_en_store,
+	.enabled = 1,
+};
+
+static struct attribute *vdd_rstr_en_attribs[] = {
+	&vdd_rstr_en.ko_attr.attr,
+	NULL,
+};
+
+static struct attribute_group vdd_rstr_en_attribs_gp = {
+	.attrs  = vdd_rstr_en_attribs,
+};
+
+static int vdd_rstr_reg_value_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int val = 0;
+	struct rail *reg = VDD_RSTR_REG_VALUE_FROM_ATTRIBS(attr);
+	/* -1:disabled, -2:fail to get regualtor handle */
+	if (reg->curr_level < 0)
+		val = reg->curr_level;
+	else
+		val = reg->levels[reg->curr_level];
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", reg->levels[reg->curr_level]);
+}
+
+static int vdd_rstr_reg_level_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct rail *reg = VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr);
+	return snprintf(buf, PAGE_SIZE, "%d\n", reg->curr_level);
+}
+
+static ssize_t vdd_rstr_reg_level_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	int val = 0;
+
+	struct rail *reg = VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr);
+
+	mutex_lock(&vdd_rstr_mutex);
+	if (vdd_rstr_en.enabled == 0)
+		goto done_store_level;
+
+	ret = kstrtoint(buf, 10, &val);
+	if (ret) {
+		pr_err("Invalid input %s for level\n", buf);
+		goto done_store_level;
+	}
+
+	if (val < 0 || val > reg->num_levels - 1) {
+		pr_err(" Invalid number %d for level\n", val);
+		goto done_store_level;
+	}
+
+	if (val != reg->curr_level) {
+		if (reg->freq_req == 1 && freq_table_get)
+			update_cpu_min_freq_all(reg->levels[val]);
+		else {
+			ret = vdd_restriction_apply_voltage(reg, val);
+			if (ret) {
+				pr_err( \
+				"Set vdd restriction for regulator %s failed\n",
+				reg->name);
+				goto done_store_level;
+			}
+		}
+		reg->curr_level = val;
+	}
+
+done_store_level:
+	mutex_unlock(&vdd_rstr_mutex);
+	return count;
+}
+
+static int psm_reg_mode_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+	return snprintf(buf, PAGE_SIZE, "%d\n", reg->mode);
+}
+
+static ssize_t psm_reg_mode_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	int val = 0;
+	struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+
+	mutex_lock(&psm_mutex);
+	ret = kstrtoint(buf, 10, &val);
+	if (ret) {
+		pr_err("Invalid input %s for mode\n", buf);
+		goto done_psm_store;
+	}
+
+	if ((val != PMIC_PWM_MODE) && (val != PMIC_AUTO_MODE)) {
+		pr_err(" Invalid number %d for mode\n", val);
+		goto done_psm_store;
+	}
+
+	if (val != reg->mode) {
+		ret = rpm_regulator_set_mode(reg->reg, val);
+		if (ret) {
+			pr_err( \
+			"Fail to set PMIC SW Mode:%d for %s\n",
+			val, reg->name);
+			goto done_psm_store;
+		}
+		reg->mode = val;
+	}
+
+done_psm_store:
+	mutex_unlock(&psm_mutex);
+	return count;
+}
 
 static int msm_thermal_get_freq_table(void)
 {
@@ -42,7 +472,7 @@
 
 	table = cpufreq_frequency_get_table(0);
 	if (table == NULL) {
-		pr_debug("%s: error reading cpufreq table\n", __func__);
+		pr_debug("%s: error reading cpufreq table\n", KBUILD_MODNAME);
 		ret = -EINVAL;
 		goto fail;
 	}
@@ -67,17 +497,166 @@
 
 	limited_max_freq = max_freq;
 	if (max_freq != MSM_CPUFREQ_NO_LIMIT)
-		pr_info("msm_thermal: Limiting cpu%d max frequency to %d\n",
-				cpu, max_freq);
+		pr_info("%s: Limiting cpu%d max frequency to %d\n",
+				KBUILD_MODNAME, cpu, max_freq);
 	else
-		pr_info("msm_thermal: Max frequency reset for cpu%d\n", cpu);
+		pr_info("%s: Max frequency reset for cpu%d\n",
+				KBUILD_MODNAME, cpu);
 
 	ret = cpufreq_update_policy(cpu);
 
 	return ret;
 }
 
-static void check_temp(struct work_struct *work)
+static void __cpuinit do_core_control(long temp)
+{
+	int i = 0;
+	int ret = 0;
+
+	if (!core_control_enabled)
+		return;
+
+	mutex_lock(&core_control_mutex);
+	if (msm_thermal_info.core_control_mask &&
+		temp >= msm_thermal_info.core_limit_temp_degC) {
+		for (i = num_possible_cpus(); i > 0; i--) {
+			if (!(msm_thermal_info.core_control_mask & BIT(i)))
+				continue;
+			if (cpus_offlined & BIT(i) && !cpu_online(i))
+				continue;
+			pr_info("%s: Set Offline: CPU%d Temp: %ld\n",
+					KBUILD_MODNAME, i, temp);
+			ret = cpu_down(i);
+			if (ret)
+				pr_err("%s: Error %d offline core %d\n",
+					KBUILD_MODNAME, ret, i);
+			cpus_offlined |= BIT(i);
+			break;
+		}
+	} else if (msm_thermal_info.core_control_mask && cpus_offlined &&
+		temp <= (msm_thermal_info.core_limit_temp_degC -
+			msm_thermal_info.core_temp_hysteresis_degC)) {
+		for (i = 0; i < num_possible_cpus(); i++) {
+			if (!(cpus_offlined & BIT(i)))
+				continue;
+			cpus_offlined &= ~BIT(i);
+			pr_info("%s: Allow Online CPU%d Temp: %ld\n",
+					KBUILD_MODNAME, i, temp);
+			/* If this core is already online, then bring up the
+			 * next offlined core.
+			 */
+			if (cpu_online(i))
+				continue;
+			ret = cpu_up(i);
+			if (ret)
+				pr_err("%s: Error %d online core %d\n",
+						KBUILD_MODNAME, ret, i);
+			break;
+		}
+	}
+	mutex_unlock(&core_control_mutex);
+}
+
+static int do_vdd_restriction(void)
+{
+	struct tsens_device tsens_dev;
+	long temp = 0;
+	int ret = 0;
+	int i = 0;
+	int dis_cnt = 0;
+
+	if (!vdd_rstr_enabled)
+		return ret;
+
+	if (usefreq && !freq_table_get) {
+		if (check_freq_table())
+			return ret;
+	}
+
+	mutex_lock(&vdd_rstr_mutex);
+	for (i = 0; i < max_tsens_num; i++) {
+		tsens_dev.sensor_num = i;
+		ret = tsens_get_temp(&tsens_dev, &temp);
+		if (ret) {
+			pr_debug("%s: Unable to read TSENS sensor %d\n",
+					__func__, tsens_dev.sensor_num);
+			dis_cnt++;
+			continue;
+		}
+		if (temp <=  msm_thermal_info.vdd_rstr_temp_hyst_degC &&
+				vdd_rstr_en.enabled == 0) {
+			ret = vdd_restriction_apply_all(1);
+			if (ret) {
+				pr_err( \
+				"Enable vdd rstr votlage for all failed\n");
+				goto exit;
+			}
+			vdd_rstr_en.enabled = 1;
+			goto exit;
+		} else if (temp > msm_thermal_info.vdd_rstr_temp_degC &&
+				vdd_rstr_en.enabled == 1)
+			dis_cnt++;
+	}
+	if (dis_cnt == max_tsens_num) {
+		ret = vdd_restriction_apply_all(0);
+		if (ret) {
+			pr_err("Disable vdd rstr votlage for all failed\n");
+			goto exit;
+		}
+		vdd_rstr_en.enabled = 0;
+	}
+exit:
+	mutex_unlock(&vdd_rstr_mutex);
+	return ret;
+}
+
+static int do_psm(void)
+{
+	struct tsens_device tsens_dev;
+	long temp = 0;
+	int ret = 0;
+	int i = 0;
+	int auto_cnt = 0;
+
+	mutex_lock(&psm_mutex);
+	for (i = 0; i < max_tsens_num; i++) {
+		tsens_dev.sensor_num = i;
+		ret = tsens_get_temp(&tsens_dev, &temp);
+		if (ret) {
+			pr_debug("%s: Unable to read TSENS sensor %d\n",
+					__func__, tsens_dev.sensor_num);
+			auto_cnt++;
+			continue;
+		}
+
+		/* As long as one sensor is above the threshold, set PWM mode
+		 * on all rails, and loop stops. Set auto mode when all rails
+		 * are below thershold */
+		if (temp >  msm_thermal_info.psm_temp_degC) {
+			ret = psm_set_mode_all(PMIC_PWM_MODE);
+			if (ret) {
+				pr_err("Set pwm mode for all failed\n");
+				goto exit;
+			}
+			break;
+		} else if (temp <= msm_thermal_info.psm_temp_hyst_degC)
+			auto_cnt++;
+	}
+
+	if (auto_cnt == max_tsens_num) {
+		ret = psm_set_mode_all(PMIC_AUTO_MODE);
+		if (ret) {
+			pr_err("Set auto mode for all failed\n");
+			goto exit;
+		}
+	}
+
+exit:
+	mutex_unlock(&psm_mutex);
+	return ret;
+}
+
+static void __cpuinit check_temp(struct work_struct *work)
 {
 	static int limit_init;
 	struct tsens_device tsens_dev;
@@ -85,12 +664,11 @@
 	uint32_t max_freq = limited_max_freq;
 	int cpu = 0;
 	int ret = 0;
-
 	tsens_dev.sensor_num = msm_thermal_info.sensor_id;
 	ret = tsens_get_temp(&tsens_dev, &temp);
 	if (ret) {
-		pr_debug("msm_thermal: Unable to read TSENS sensor %d\n",
-				tsens_dev.sensor_num);
+		pr_debug("%s: Unable to read TSENS sensor %d\n",
+				KBUILD_MODNAME, tsens_dev.sensor_num);
 		goto reschedule;
 	}
 
@@ -102,6 +680,10 @@
 			limit_init = 1;
 	}
 
+	do_core_control(temp);
+	do_vdd_restriction();
+	do_psm();
+
 	if (temp >= msm_thermal_info.limit_temp_degC) {
 		if (limit_idx == limit_idx_low)
 			goto reschedule;
@@ -129,8 +711,9 @@
 	for_each_possible_cpu(cpu) {
 		ret = update_cpu_max_freq(cpu, max_freq);
 		if (ret)
-			pr_debug("Unable to limit cpu%d max freq to %d\n",
-					cpu, max_freq);
+			pr_debug(
+			"%s: Unable to limit cpu%d max freq to %d\n",
+					KBUILD_MODNAME, cpu, max_freq);
 	}
 
 reschedule:
@@ -139,7 +722,36 @@
 				msecs_to_jiffies(msm_thermal_info.poll_ms));
 }
 
-static void disable_msm_thermal(void)
+static int __cpuinit msm_thermal_cpu_callback(struct notifier_block *nfb,
+		unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
+		if (core_control_enabled &&
+			(msm_thermal_info.core_control_mask & BIT(cpu)) &&
+			(cpus_offlined & BIT(cpu))) {
+			pr_info(
+			"%s: Preventing cpu%d from coming online.\n",
+				KBUILD_MODNAME, cpu);
+			return NOTIFY_BAD;
+		}
+	}
+
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata msm_thermal_cpu_notifier = {
+	.notifier_call = msm_thermal_cpu_callback,
+};
+
+/**
+ * We will reset the cpu frequencies limits here. The core online/offline
+ * status will be carried over to the process stopping the msm_thermal, as
+ * we dont want to online a core and bring in the thermal issues.
+ */
+static void __cpuinit disable_msm_thermal(void)
 {
 	int cpu = 0;
 
@@ -155,7 +767,7 @@
 	}
 }
 
-static int set_enabled(const char *val, const struct kernel_param *kp)
+static int __cpuinit set_enabled(const char *val, const struct kernel_param *kp)
 {
 	int ret = 0;
 
@@ -163,9 +775,10 @@
 	if (!enabled)
 		disable_msm_thermal();
 	else
-		pr_info("msm_thermal: no action for enabled = %d\n", enabled);
+		pr_info("%s: no action for enabled = %d\n",
+				KBUILD_MODNAME, enabled);
 
-	pr_info("msm_thermal: enabled = %d\n", enabled);
+	pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
 
 	return ret;
 }
@@ -178,18 +791,561 @@
 module_param_cb(enabled, &module_ops, &enabled, 0644);
 MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
 
+
+/* Call with core_control_mutex locked */
+static int __cpuinit update_offline_cores(int val)
+{
+	int cpu = 0;
+	int ret = 0;
+
+	cpus_offlined = msm_thermal_info.core_control_mask & val;
+	if (!core_control_enabled)
+		return 0;
+
+	for_each_possible_cpu(cpu) {
+		if (!(cpus_offlined & BIT(cpu)))
+			continue;
+		if (!cpu_online(cpu))
+			continue;
+		ret = cpu_down(cpu);
+		if (ret)
+			pr_err("%s: Unable to offline cpu%d\n",
+				KBUILD_MODNAME, cpu);
+	}
+	return ret;
+}
+
+static ssize_t show_cc_enabled(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", core_control_enabled);
+}
+
+static ssize_t __cpuinit store_cc_enabled(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	int val = 0;
+
+	mutex_lock(&core_control_mutex);
+	ret = kstrtoint(buf, 10, &val);
+	if (ret) {
+		pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
+		goto done_store_cc;
+	}
+
+	if (core_control_enabled == !!val)
+		goto done_store_cc;
+
+	core_control_enabled = !!val;
+	if (core_control_enabled) {
+		pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
+		register_cpu_notifier(&msm_thermal_cpu_notifier);
+		update_offline_cores(cpus_offlined);
+	} else {
+		pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
+		unregister_cpu_notifier(&msm_thermal_cpu_notifier);
+	}
+
+done_store_cc:
+	mutex_unlock(&core_control_mutex);
+	return count;
+}
+
+static ssize_t show_cpus_offlined(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", cpus_offlined);
+}
+
+static ssize_t __cpuinit store_cpus_offlined(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	uint32_t val = 0;
+
+	mutex_lock(&core_control_mutex);
+	ret = kstrtouint(buf, 10, &val);
+	if (ret) {
+		pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
+		goto done_cc;
+	}
+
+	if (enabled) {
+		pr_err("%s: Ignoring request; polling thread is enabled.\n",
+				KBUILD_MODNAME);
+		goto done_cc;
+	}
+
+	if (cpus_offlined == val)
+		goto done_cc;
+
+	update_offline_cores(val);
+done_cc:
+	mutex_unlock(&core_control_mutex);
+	return count;
+}
+
+static __cpuinitdata struct kobj_attribute cc_enabled_attr =
+__ATTR(enabled, 0644, show_cc_enabled, store_cc_enabled);
+
+static __cpuinitdata struct kobj_attribute cpus_offlined_attr =
+__ATTR(cpus_offlined, 0644, show_cpus_offlined, store_cpus_offlined);
+
+static __cpuinitdata struct attribute *cc_attrs[] = {
+	&cc_enabled_attr.attr,
+	&cpus_offlined_attr.attr,
+	NULL,
+};
+
+static __cpuinitdata struct attribute_group cc_attr_group = {
+	.attrs = cc_attrs,
+};
+
+static __init int msm_thermal_add_cc_nodes(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *cc_kobj = NULL;
+	int ret = 0;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module\n",
+			KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto done_cc_nodes;
+	}
+
+	cc_kobj = kobject_create_and_add("core_control", module_kobj);
+	if (!cc_kobj) {
+		pr_err("%s: cannot create core control kobj\n",
+				KBUILD_MODNAME);
+		ret = -ENOMEM;
+		goto done_cc_nodes;
+	}
+
+	ret = sysfs_create_group(cc_kobj, &cc_attr_group);
+	if (ret) {
+		pr_err("%s: cannot create group\n", KBUILD_MODNAME);
+		goto done_cc_nodes;
+	}
+
+	return 0;
+
+done_cc_nodes:
+	if (cc_kobj)
+		kobject_del(cc_kobj);
+	return ret;
+}
+
 int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	int ret = 0;
 
 	BUG_ON(!pdata);
-	BUG_ON(pdata->sensor_id >= TSENS_MAX_SENSORS);
+	tsens_get_max_sensor_num(&max_tsens_num);
+	BUG_ON(msm_thermal_info.sensor_id >= max_tsens_num);
 	memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
 
 	enabled = 1;
+	core_control_enabled = 1;
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 	schedule_delayed_work(&check_temp_work, 0);
 
+	register_cpu_notifier(&msm_thermal_cpu_notifier);
+
+	return ret;
+}
+
+static int vdd_restriction_reg_init(struct platform_device *pdev)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < rails_cnt; i++) {
+		if (rails[i].freq_req == 1) {
+			usefreq |= BIT(i);
+			check_freq_table();
+			/* Restrict frequency by default until we have made
+			 * our first temp reading */
+			if (freq_table_get)
+				ret = vdd_restriction_apply_freq(&rails[i], 0);
+			else
+				pr_info("%s:Defer vdd rstr freq init\n",
+						__func__);
+		} else {
+			rails[i].reg = devm_regulator_get(&pdev->dev,
+					rails[i].name);
+			if (IS_ERR_OR_NULL(rails[i].reg)) {
+				ret = PTR_ERR(rails[i].reg);
+				if (ret != -EPROBE_DEFER) {
+					pr_err( \
+					"%s, could not get regulator: %s\n",
+					rails[i].name, __func__);
+					rails[i].reg = NULL;
+					rails[i].curr_level = -2;
+					return ret;
+				}
+				return ret;
+			}
+			/* Restrict votlage by default until we have made
+			 * our first temp reading */
+			ret = vdd_restriction_apply_voltage(&rails[i], 0);
+		}
+	}
+
+	return ret;
+}
+
+static int psm_reg_init(struct platform_device *pdev)
+{
+	int ret = 0;
+	int i = 0;
+	int j = 0;
+
+	for (i = 0; i < psm_rails_cnt; i++) {
+		psm_rails[i].reg = rpm_regulator_get(&pdev->dev,
+				psm_rails[i].name);
+		if (IS_ERR_OR_NULL(psm_rails[i].reg)) {
+			ret = PTR_ERR(psm_rails[i].reg);
+			if (ret != -EPROBE_DEFER) {
+				pr_err("%s, could not get rpm regulator: %s\n",
+					psm_rails[i].name, __func__);
+				psm_rails[i].reg = NULL;
+				goto psm_reg_exit;
+			}
+			return ret;
+		}
+		/* Apps default vote for PWM mode */
+		psm_rails[i].init = PMIC_PWM_MODE;
+		ret = rpm_regulator_set_mode(psm_rails[i].reg,
+				psm_rails[i].init);
+		if (ret) {
+			pr_err("%s: Cannot set PMIC PWM mode\n", __func__);
+			return ret;
+		} else
+			psm_rails[i].mode = PMIC_PWM_MODE;
+	}
+
+	return ret;
+
+psm_reg_exit:
+	if (ret) {
+		for (j = 0; j < i; j++) {
+			if (psm_rails[j].reg != NULL)
+				rpm_regulator_put(psm_rails[j].reg);
+		}
+	}
+
+	return ret;
+}
+
+static int msm_thermal_add_vdd_rstr_nodes(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *vdd_rstr_kobj = NULL;
+	struct kobject *vdd_rstr_reg_kobj[MAX_RAILS] = {0};
+	int rc = 0;
+	int i = 0;
+
+	if (!vdd_rstr_probed) {
+		vdd_rstr_nodes_called = true;
+		return rc;
+	}
+
+	if (vdd_rstr_probed && rails_cnt == 0)
+		return rc;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		rc = -ENOENT;
+		goto thermal_sysfs_add_exit;
+	}
+
+	vdd_rstr_kobj = kobject_create_and_add("vdd_restriction", module_kobj);
+	if (!vdd_rstr_kobj) {
+		pr_err("%s: cannot create vdd_restriction kobject\n", __func__);
+		rc = -ENOMEM;
+		goto thermal_sysfs_add_exit;
+	}
+
+	rc = sysfs_create_group(vdd_rstr_kobj, &vdd_rstr_en_attribs_gp);
+	if (rc) {
+		pr_err("%s: cannot create kobject attribute group\n", __func__);
+		rc = -ENOMEM;
+		goto thermal_sysfs_add_exit;
+	}
+
+	for (i = 0; i < rails_cnt; i++) {
+		vdd_rstr_reg_kobj[i] = kobject_create_and_add(rails[i].name,
+					vdd_rstr_kobj);
+		if (!vdd_rstr_reg_kobj[i]) {
+			pr_err("%s: cannot create for kobject for %s\n",
+					__func__, rails[i].name);
+			rc = -ENOMEM;
+			goto thermal_sysfs_add_exit;
+		}
+
+		rails[i].attr_gp.attrs = kzalloc(sizeof(struct attribute *) * 3,
+					GFP_KERNEL);
+		if (!rails[i].attr_gp.attrs) {
+			rc = -ENOMEM;
+			goto thermal_sysfs_add_exit;
+		}
+
+		VDD_RES_RW_ATTRIB(rails[i], rails[i].level_attr, 0, level);
+		VDD_RES_RO_ATTRIB(rails[i], rails[i].value_attr, 1, value);
+		rails[i].attr_gp.attrs[2] = NULL;
+
+		rc = sysfs_create_group(vdd_rstr_reg_kobj[i],
+				&rails[i].attr_gp);
+		if (rc) {
+			pr_err("%s: cannot create attribute group for %s\n",
+					__func__, rails[i].name);
+			goto thermal_sysfs_add_exit;
+		}
+	}
+
+	return rc;
+
+thermal_sysfs_add_exit:
+	if (rc) {
+		for (i = 0; i < rails_cnt; i++) {
+			kobject_del(vdd_rstr_reg_kobj[i]);
+			kfree(rails[i].attr_gp.attrs);
+		}
+		if (vdd_rstr_kobj)
+			kobject_del(vdd_rstr_kobj);
+	}
+	return rc;
+}
+
+static int msm_thermal_add_psm_nodes(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *psm_kobj = NULL;
+	struct kobject *psm_reg_kobj[MAX_RAILS] = {0};
+	int rc = 0;
+	int i = 0;
+
+	if (!psm_probed) {
+		psm_nodes_called = true;
+		return rc;
+	}
+
+	if (psm_probed && psm_rails_cnt == 0)
+		return rc;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		rc = -ENOENT;
+		goto psm_node_exit;
+	}
+
+	psm_kobj = kobject_create_and_add("pmic_sw_mode", module_kobj);
+	if (!psm_kobj) {
+		pr_err("%s: cannot create psm kobject\n", KBUILD_MODNAME);
+		rc = -ENOMEM;
+		goto psm_node_exit;
+	}
+
+	for (i = 0; i < psm_rails_cnt; i++) {
+		psm_reg_kobj[i] = kobject_create_and_add(psm_rails[i].name,
+					psm_kobj);
+		if (!psm_reg_kobj[i]) {
+			pr_err("%s: cannot create for kobject for %s\n",
+					KBUILD_MODNAME, psm_rails[i].name);
+			rc = -ENOMEM;
+			goto psm_node_exit;
+		}
+		psm_rails[i].attr_gp.attrs = kzalloc( \
+				sizeof(struct attribute *) * 2, GFP_KERNEL);
+		if (!psm_rails[i].attr_gp.attrs) {
+			rc = -ENOMEM;
+			goto psm_node_exit;
+		}
+
+		PSM_RW_ATTRIB(psm_rails[i], psm_rails[i].mode_attr, 0, mode);
+		psm_rails[i].attr_gp.attrs[1] = NULL;
+
+		rc = sysfs_create_group(psm_reg_kobj[i], &psm_rails[i].attr_gp);
+		if (rc) {
+			pr_err("%s: cannot create attribute group for %s\n",
+					KBUILD_MODNAME, psm_rails[i].name);
+			goto psm_node_exit;
+		}
+	}
+
+	return rc;
+
+psm_node_exit:
+	if (rc) {
+		for (i = 0; i < psm_rails_cnt; i++) {
+			kobject_del(psm_reg_kobj[i]);
+			kfree(psm_rails[i].attr_gp.attrs);
+		}
+		if (psm_kobj)
+			kobject_del(psm_kobj);
+	}
+	return rc;
+}
+
+static int probe_vdd_rstr(struct device_node *node,
+		struct msm_thermal_data *data, struct platform_device *pdev)
+{
+	int ret = 0;
+	int i = 0;
+	int arr_size;
+	char *key = NULL;
+	struct device_node *child_node = NULL;
+
+	key = "qcom,vdd-restriction-temp";
+	ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,vdd-restriction-temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_hyst_degC);
+	if (ret)
+		goto read_node_fail;
+
+	for_each_child_of_node(node, child_node) {
+		rails_cnt++;
+	}
+
+	if (rails_cnt == 0)
+		goto read_node_fail;
+	if (rails_cnt >= MAX_RAILS) {
+		pr_err("%s: Too many rails.\n", __func__);
+		return -EFAULT;
+	}
+
+	rails = kzalloc(sizeof(struct rail) * rails_cnt,
+				GFP_KERNEL);
+	if (!rails) {
+		pr_err("%s: Fail to allocate memory for rails.\n", __func__);
+		return -ENOMEM;
+	}
+
+	i = 0;
+	for_each_child_of_node(node, child_node) {
+		key = "qcom,vdd-rstr-reg";
+		ret = of_property_read_string(child_node, key, &rails[i].name);
+		if (ret)
+			goto read_node_fail;
+
+		key = "qcom,levels";
+		if (!of_get_property(child_node, key, &arr_size))
+			goto read_node_fail;
+		rails[i].num_levels = arr_size/sizeof(__be32);
+		if (rails[i].num_levels >
+			sizeof(rails[i].levels)/sizeof(uint32_t)) {
+			pr_err("%s: Array size too large\n", __func__);
+			return -EFAULT;
+		}
+		ret = of_property_read_u32_array(child_node, key,
+				rails[i].levels, rails[i].num_levels);
+		if (ret)
+			goto read_node_fail;
+
+		key = "qcom,min-level";
+		ret = of_property_read_u32(child_node, key,
+				&rails[i].min_level);
+		if (ret)
+			goto read_node_fail;
+
+		key = "qcom,freq-req";
+		rails[i].freq_req = of_property_read_bool(child_node, key);
+
+		if (ret)
+			goto read_node_fail;
+		rails[i].curr_level = 0;
+		rails[i].reg = NULL;
+		i++;
+	}
+
+	if (rails_cnt) {
+		ret = vdd_restriction_reg_init(pdev);
+		if (ret) {
+			pr_info("%s:Failed to get regulators. KTM continues.\n",
+				__func__);
+			goto read_node_fail;
+		}
+		vdd_rstr_enabled = true;
+	}
+read_node_fail:
+	vdd_rstr_probed = true;
+	if (ret) {
+		dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+			__func__, node->full_name, key);
+		kfree(rails);
+		rails_cnt = 0;
+	}
+	if (ret == -EPROBE_DEFER)
+		vdd_rstr_probed = false;
+	return ret;
+}
+
+static int probe_psm(struct device_node *node, struct msm_thermal_data *data,
+		struct platform_device *pdev)
+{
+	int ret = 0;
+	int j = 0;
+	char *key = NULL;
+
+	key = "qcom,pmic-sw-mode-temp";
+	ret = of_property_read_u32(node, key, &data->psm_temp_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,pmic-sw-mode-temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data->psm_temp_hyst_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,pmic-sw-mode-regs";
+	psm_rails_cnt = of_property_count_strings(node, key);
+	psm_rails = kzalloc(sizeof(struct psm_rail) * psm_rails_cnt,
+			GFP_KERNEL);
+	if (!psm_rails) {
+		pr_err("%s: Fail to allocate memory for psm rails\n", __func__);
+		psm_rails_cnt = 0;
+		return -ENOMEM;
+	}
+
+	for (j = 0; j < psm_rails_cnt; j++) {
+		ret = of_property_read_string_index(node, key, j,
+				&psm_rails[j].name);
+		if (ret)
+			goto read_node_fail;
+	}
+
+	if (psm_rails_cnt) {
+		ret = psm_reg_init(pdev);
+		if (ret) {
+			pr_info("%s:Failed to get regulators. KTM continues.\n",
+					__func__);
+			goto read_node_fail;
+		}
+		psm_enabled = true;
+	}
+
+read_node_fail:
+	psm_probed = true;
+	if (ret) {
+		dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+			__func__, node->full_name, key);
+		kfree(psm_rails);
+		psm_rails_cnt = 0;
+	}
+	if (ret == -EPROBE_DEFER)
+		psm_probed = false;
 	return ret;
 }
 
@@ -198,14 +1354,15 @@
 	int ret = 0;
 	char *key = NULL;
 	struct device_node *node = pdev->dev.of_node;
+
 	struct msm_thermal_data data;
 
 	memset(&data, 0, sizeof(struct msm_thermal_data));
+
 	key = "qcom,sensor-id";
 	ret = of_property_read_u32(node, key, &data.sensor_id);
 	if (ret)
 		goto fail;
-	WARN_ON(data.sensor_id >= TSENS_MAX_SENSORS);
 
 	key = "qcom,poll-ms";
 	ret = of_property_read_u32(node, key, &data.poll_ms);
@@ -224,17 +1381,50 @@
 
 	key = "qcom,freq-step";
 	ret = of_property_read_u32(node, key, &data.freq_step);
+	if (ret)
+		goto fail;
 
+	key = "qcom,core-limit-temp";
+	ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
+
+	key = "qcom,core-temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data.core_temp_hysteresis_degC);
+
+	key = "qcom,core-control-mask";
+	ret = of_property_read_u32(node, key, &data.core_control_mask);
+
+	/* Probe optional properties below. Call probe_psm before
+	 * probe_vdd_rstr because rpm_regulator_get has to be called
+	 * before devm_regulator_get*/
+	ret = probe_psm(node, &data, pdev);
+	if (ret == -EPROBE_DEFER)
+		goto fail;
+	ret = probe_vdd_rstr(node, &data, pdev);
+	if (ret == -EPROBE_DEFER)
+		goto fail;
+
+	/* In case sysfs add nodes get called before probe function.
+	 * Need to make sure sysfs node is created again */
+	if (psm_nodes_called) {
+		msm_thermal_add_psm_nodes();
+		psm_nodes_called = false;
+	}
+	if (vdd_rstr_nodes_called) {
+		msm_thermal_add_vdd_rstr_nodes();
+		vdd_rstr_nodes_called = false;
+	}
+	ret = msm_thermal_init(&data);
+
+	return ret;
 fail:
 	if (ret)
 		pr_err("%s: Failed reading node=%s, key=%s\n",
-		       __func__, node->full_name, key);
-	else
-		ret = msm_thermal_init(&data);
+			__func__, node->full_name, key);
 
 	return ret;
 }
 
+
 static struct of_device_id msm_thermal_match_table[] = {
 	{.compatible = "qcom,msm-thermal"},
 	{},
@@ -253,3 +1443,14 @@
 {
 	return platform_driver_register(&msm_thermal_device_driver);
 }
+
+int __init msm_thermal_late_init(void)
+{
+	msm_thermal_add_cc_nodes();
+	msm_thermal_add_psm_nodes();
+	msm_thermal_add_vdd_rstr_nodes();
+
+	return 0;
+}
+late_initcall(msm_thermal_late_init);
+
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 867e218..ad7c702 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -631,7 +631,7 @@
 		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
 		return ret;
 	}
-	/* Register callback event for EOT (End of transfer) event. */
+	/* Register callback event for DESC_DONE event. */
 	ret = sps_register_event(sps_pipe_handle, sps_event);
 	if (ret) {
 		pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
@@ -964,7 +964,10 @@
 		 */
 		mb();
 		if (is_blsp_uart(msm_uport)) {
-			sps_disconnect(sps_pipe_handle);
+			ret = sps_disconnect(sps_pipe_handle);
+			if (ret)
+				pr_err("%s(): sps_disconnect failed\n",
+							__func__);
 			msm_hs_spsconnect_rx(uport);
 			msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
 		} else {
@@ -1023,8 +1026,12 @@
 						disconnect_rx_endpoint);
 	struct msm_hs_rx *rx = &msm_uport->rx;
 	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+	int ret = 0;
 
-	sps_disconnect(sps_pipe_handle);
+	ret = sps_disconnect(sps_pipe_handle);
+	if (ret)
+		pr_err("%s(): sps_disconnect failed\n", __func__);
+
 	wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
 	msm_uport->rx.flush = FLUSH_SHUTDOWN;
 	wake_up(&msm_uport->rx.wait);
@@ -1158,7 +1165,7 @@
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct msm_hs_rx *rx = &msm_uport->rx;
 	struct sps_pipe *sps_pipe_handle;
-	u32 flags = SPS_IOVEC_FLAG_EOT;
+	u32 flags = SPS_IOVEC_FLAG_INT;
 	unsigned int buffer_pending = msm_uport->rx.buffer_pending;
 	unsigned int data;
 
@@ -1284,7 +1291,7 @@
 	struct sps_event_notify *notify;
 	struct msm_hs_rx *rx;
 	struct sps_pipe *sps_pipe_handle;
-	u32 sps_flags = SPS_IOVEC_FLAG_EOT;
+	u32 sps_flags = SPS_IOVEC_FLAG_INT;
 
 	msm_uport = container_of((struct tasklet_struct *)tlet_ptr,
 				 struct msm_hs_port, rx.tlet);
@@ -1699,8 +1706,6 @@
 	int ret;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct circ_buf *tx_buf = &uport->state->xmit;
-	struct msm_hs_rx *rx = &msm_uport->rx;
-	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
 
 	mutex_lock(&msm_uport->clk_mutex);
 	spin_lock_irqsave(&uport->lock, flags);
@@ -1745,7 +1750,6 @@
 		if (is_blsp_uart(msm_uport)) {
 			msm_uport->clk_req_off_state =
 				CLK_REQ_OFF_RXSTALE_FLUSHED;
-			sps_disconnect(sps_pipe_handle);
 		}
 		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* RXSTALE flush not complete - retry */
@@ -2654,7 +2658,7 @@
 		sps_config->mode = SPS_MODE_SRC;
 		sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index;
 		sps_config->dest_pipe_index = 0;
-		sps_config->options = SPS_O_EOT;
+		sps_config->options = SPS_O_DESC_DONE;
 	} else {
 		/* For UART consumer transfer, source is system memory
 		where as destination is UART peripheral */
@@ -2682,11 +2686,14 @@
 	memset(sps_config->desc.base, 0x00, sps_config->desc.size);
 
 	sps_event->mode = SPS_TRIGGER_CALLBACK;
-	sps_event->options = SPS_O_EOT;
-	if (is_producer)
+
+	if (is_producer) {
 		sps_event->callback = msm_hs_sps_rx_callback;
-	else
+		sps_event->options = SPS_O_DESC_DONE;
+	} else {
 		sps_event->callback = msm_hs_sps_tx_callback;
+		sps_event->options = SPS_O_EOT;
+	}
 
 	sps_event->user = (void *)msm_uport;
 
@@ -3160,7 +3167,10 @@
 				pr_err("%s():HSUART TX Stalls.\n", __func__);
 		} else {
 			/* BAM Disconnect for TX */
-			sps_disconnect(sps_pipe_handle);
+			ret = sps_disconnect(sps_pipe_handle);
+			if (ret)
+				pr_err("%s(): sps_disconnect failed\n",
+							__func__);
 		}
 	}
 	tasklet_kill(&msm_uport->tx.tlet);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f83794c..7a6765b 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1254,50 +1254,11 @@
 	return ret;
 }
 
-/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
-static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *msm)
+/* Reinitialize SSPHY parameters by overriding using QSCRATCH CR interface */
+static void dwc3_msm_ss_phy_reg_init(struct dwc3_msm *msm)
 {
 	u32 data = 0;
 
-	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
-	msleep(30);
-	/* Assert SSPHY reset */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
-	usleep_range(2000, 2200);
-	/* De-assert SSPHY reset - power and ref_clock must be ON */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
-	usleep_range(2000, 2200);
-	/* Ref clock must be stable now, enable ref clock for HS mode */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
-	usleep_range(2000, 2200);
-	/*
-	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
-	 * and disable RETENTION (power-on default is ENABLED)
-	 */
-	dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
-	usleep_range(2000, 2200);
-	/* Disable (bypass) VBUS and ID filters */
-	dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
-	/*
-	 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
-	 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
-	 * preempasis and rise/fall time.
-	 */
-	if (override_phy_init)
-		msm->hsphy_init_seq = override_phy_init;
-	if (msm->hsphy_init_seq)
-		dwc3_msm_write_readback(msm->base,
-					PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
-					msm->hsphy_init_seq & 0x03FFFFFF);
-
-	/* Enable master clock for RAMs to allow BAM to access RAMs when
-	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
-	 * are seen where RAM clocks get turned OFF in SS mode
-	 */
-	dwc3_msm_write_reg(msm->base, CGCTL_REG,
-		dwc3_msm_read_reg(msm->base, CGCTL_REG) | 0x18);
-
 	/*
 	 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
 	 * in HS mode instead of SS mode. Workaround it by asserting
@@ -1344,6 +1305,51 @@
 	dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
 }
 
+/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *msm)
+{
+	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+	msleep(30);
+	/* Assert SSPHY reset */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
+	usleep_range(2000, 2200);
+	/* De-assert SSPHY reset - power and ref_clock must be ON */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+	usleep_range(2000, 2200);
+	/* Ref clock must be stable now, enable ref clock for HS mode */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
+	usleep_range(2000, 2200);
+	/*
+	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
+	 * and disable RETENTION (power-on default is ENABLED)
+	 */
+	dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
+	usleep_range(2000, 2200);
+	/* Disable (bypass) VBUS and ID filters */
+	dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
+	/*
+	 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
+	 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
+	 * preempasis and rise/fall time.
+	 */
+	if (override_phy_init)
+		msm->hsphy_init_seq = override_phy_init;
+	if (msm->hsphy_init_seq)
+		dwc3_msm_write_readback(msm->base,
+					PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
+					msm->hsphy_init_seq & 0x03FFFFFF);
+
+	/* Enable master clock for RAMs to allow BAM to access RAMs when
+	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
+	 * are seen where RAM clocks get turned OFF in SS mode
+	 */
+	dwc3_msm_write_reg(msm->base, CGCTL_REG,
+		dwc3_msm_read_reg(msm->base, CGCTL_REG) | 0x18);
+
+	dwc3_msm_ss_phy_reg_init(msm);
+}
+
 static void dwc3_msm_block_reset(bool core_reset)
 {
 
@@ -1791,6 +1797,11 @@
 	udelay(10);
 	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
 
+	/*
+	 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
+	 * the internal registers to default values.
+	 */
+	dwc3_msm_ss_phy_reg_init(mdwc);
 	atomic_set(&mdwc->in_lpm, 0);
 
 	/* match disable_irq call from isr */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f060718..c08a259 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2169,7 +2169,7 @@
 	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
 	WARN_ON_ONCE(ret);
 	dep->resource_index = 0;
-
+	dep->flags &= ~DWC3_EP_BUSY;
 	udelay(100);
 }
 
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index c847ee6..763c7f6 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -135,6 +135,7 @@
 	irqreturn_t (*irq_handler)(int irq, void *ptr);
 };
 
+int mdss_register_irq(struct mdss_hw *hw);
 void mdss_enable_irq(struct mdss_hw *hw);
 void mdss_disable_irq(struct mdss_hw *hw);
 void mdss_disable_irq_nosync(struct mdss_hw *hw);
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 0b2a7c0..0918db1 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -286,6 +286,96 @@
 	return -ENODEV;
 }
 
+
+static int mdss_debug_stat_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int mdss_debug_stat_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int mdss_debug_stat_ctl_dump(struct mdss_mdp_ctl *ctl,
+		char *bp, int len)
+{
+	int tot = 0;
+
+	if (!ctl->ref_cnt)
+		return 0;
+
+	if (ctl->intf_num) {
+		tot = scnprintf(bp, len,
+			"intf%d: play: %08u \tvsync: %08u \tunderrun: %08u\n",
+				ctl->intf_num, ctl->play_cnt,
+				ctl->vsync_cnt, ctl->underrun_cnt);
+	} else {
+		tot = scnprintf(bp, len, "wb: \tmode=%x \tplay: %08u\n",
+				ctl->opmode, ctl->play_cnt);
+	}
+
+	return tot;
+}
+
+static ssize_t mdss_debug_stat_read(struct file *file, char __user *buff,
+		size_t count, loff_t *ppos)
+{
+	struct mdss_data_type *mdata = file->private_data;
+	struct mdss_mdp_pipe *pipe;
+	int i, len, tot;
+	char bp[512];
+
+	if (*ppos)
+		return 0;	/* the end */
+
+	len = sizeof(bp);
+
+	tot = scnprintf(bp, len, "\nmdp:\n");
+
+	for (i = 0; i < mdata->nctl; i++)
+		tot += mdss_debug_stat_ctl_dump(mdata->ctl_off + i,
+				bp + tot, len - tot);
+	tot += scnprintf(bp + tot, len - tot, "\n");
+
+	for (i = 0; i < mdata->nvig_pipes; i++) {
+		pipe = mdata->vig_pipes + i;
+		tot += scnprintf(bp + tot, len - tot,
+			"VIG%d :   %08u\t", i, pipe->play_cnt);
+	}
+	tot += scnprintf(bp + tot, len - tot, "\n");
+
+	for (i = 0; i < mdata->nrgb_pipes; i++) {
+		pipe = mdata->rgb_pipes + i;
+		tot += scnprintf(bp + tot, len - tot,
+			"RGB%d :   %08u\t", i, pipe->play_cnt);
+	}
+	tot += scnprintf(bp + tot, len - tot, "\n");
+
+	for (i = 0; i < mdata->ndma_pipes; i++) {
+		pipe = mdata->dma_pipes + i;
+		tot += scnprintf(bp + tot, len - tot,
+			"DMA%d :   %08u\t", i, pipe->play_cnt);
+	}
+	tot += scnprintf(bp + tot, len - tot, "\n");
+
+	if (copy_to_user(buff, bp, tot))
+		return -EFAULT;
+
+	*ppos += tot;	/* increase offset */
+
+	return tot;
+}
+
+static const struct file_operations mdss_stat_fops = {
+	.open = mdss_debug_stat_open,
+	.release = mdss_debug_stat_release,
+	.read = mdss_debug_stat_read,
+};
+
 static int mdss_debugfs_cleanup(struct mdss_debug_data *mdd)
 {
 	struct mdss_debug_base *base, *tmp;
@@ -330,6 +420,7 @@
 		mdss_debugfs_cleanup(mdd);
 		return -ENODEV;
 	}
+	debugfs_create_file("stat", 0644, mdd->root, mdata, &mdss_stat_fops);
 
 	debugfs_create_u32("min_mdp_clk", 0644, mdd->root,
 		(u32 *)&mdata->min_mdp_clk);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index ccec0fc..22ff08c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -59,6 +59,9 @@
 		mdss_dsi1_hw.ptr = (void *)(ctrl);
 		ctrl->mdss_hw = &mdss_dsi1_hw;
 	}
+
+	if (!mdss_register_irq(ctrl->mdss_hw))
+		pr_err("%s: mdss_register_irq failed.\n", __func__);
 }
 
 void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index e28a4e9..213fcff 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2734,6 +2734,10 @@
 		return rc;
 	}
 
+	rc = mdss_register_irq(&hdmi_tx_hw);
+	if (rc)
+		DEV_ERR("%s: mdss_register_irq failed.\n", __func__);
+
 	return rc;
 } /* hdmi_tx_register_panel */
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 8be64b2..51776db 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -228,6 +228,27 @@
 	return IRQ_HANDLED;
 }
 
+int mdss_register_irq(struct mdss_hw *hw)
+{
+	unsigned long irq_flags;
+	u32 ndx_bit;
+
+	if (!hw || hw->hw_ndx >= MDSS_MAX_HW_BLK)
+		return -EINVAL;
+
+	ndx_bit = BIT(hw->hw_ndx);
+
+	spin_lock_irqsave(&mdss_lock, irq_flags);
+	if (!mdss_irq_handlers[hw->hw_ndx])
+		mdss_irq_handlers[hw->hw_ndx] = hw;
+	else
+		pr_err("panel %d's irq at %p is already registered\n",
+			hw->hw_ndx, hw->irq_handler);
+	spin_unlock_irqrestore(&mdss_lock, irq_flags);
+
+	return 0;
+} /* mdss_regsiter_irq */
+EXPORT_SYMBOL(mdss_register_irq);
 
 void mdss_enable_irq(struct mdss_hw *hw)
 {
@@ -237,6 +258,11 @@
 	if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
 		return;
 
+	if (!mdss_irq_handlers[hw->hw_ndx]) {
+		pr_err("failed. First register the irq then enable it.\n");
+		return;
+	}
+
 	ndx_bit = BIT(hw->hw_ndx);
 
 	pr_debug("Enable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
@@ -247,7 +273,6 @@
 		pr_debug("MDSS HW ndx=%d is already set, mask=%x\n",
 				hw->hw_ndx, mdss_res->irq_mask);
 	} else {
-		mdss_irq_handlers[hw->hw_ndx] = hw;
 		mdss_res->irq_mask |= ndx_bit;
 		if (!mdss_res->irq_ena) {
 			mdss_res->irq_ena = true;
@@ -277,7 +302,6 @@
 			hw->hw_ndx, mdss_res->mdp_irq_mask,
 			mdss_res->mdp_hist_irq_mask);
 	} else {
-		mdss_irq_handlers[hw->hw_ndx] = NULL;
 		mdss_res->irq_mask &= ~ndx_bit;
 		if (mdss_res->irq_mask == 0) {
 			mdss_res->irq_ena = false;
@@ -1042,6 +1066,10 @@
 	if (rc)
 		pr_err("unable to register mdp instance\n");
 
+	rc = mdss_register_irq(&mdss_mdp_hw);
+	if (rc)
+		pr_err("mdss_register_irq failed.\n");
+
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_res = NULL;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 07b083a..25c5871 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -122,6 +122,7 @@
 	u32 flush_bits;
 
 	u32 play_cnt;
+	u32 vsync_cnt;
 	u32 underrun_cnt;
 
 	u16 width;
@@ -217,6 +218,21 @@
 	struct mdss_mdp_img_data p[MAX_PLANES];
 };
 
+struct pp_hist_col_info {
+	u32 col_state;
+	u32 col_en;
+	u32 read_request;
+	u32 hist_cnt_read;
+	u32 hist_cnt_sent;
+	u32 hist_cnt_time;
+	u32 frame_cnt;
+	u32 is_kick_ready;
+	struct completion comp;
+	u32 data[HIST_V_SIZE];
+	struct mutex hist_mutex;
+	spinlock_t hist_lock;
+};
+
 struct pp_sts_type {
 	u32 pa_sts;
 	u32 pcc_sts;
@@ -233,6 +249,7 @@
 struct mdss_pipe_pp_res {
 	u32 igc_c0_c1[IGC_LUT_ENTRIES];
 	u32 igc_c2[IGC_LUT_ENTRIES];
+	struct pp_hist_col_info hist;
 	struct pp_sts_type pp_sts;
 };
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index fa53656..4e51100 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -294,6 +294,8 @@
 	ctl->stop_fnc = NULL;
 	ctl->prepare_fnc = NULL;
 	ctl->display_fnc = NULL;
+	ctl->wait_fnc = NULL;
+	ctl->set_vsync_handler = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index d6b0fb2..006a8dd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -180,6 +180,7 @@
 	pr_debug("%s: ctl=%d intf_num=%d\n", __func__, ctl->num, ctl->intf_num);
 
 	vsync_time = ktime_get();
+	ctl->vsync_cnt++;
 
 	spin_lock(&ctx->vsync_lock);
 	if (ctx->vsync_handler)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 0426784..6e631e9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -282,8 +282,9 @@
 	}
 
 	vsync_time = ktime_get();
+	ctl->vsync_cnt++;
 
-	pr_debug("intr ctl=%d\n", ctl->num);
+	pr_debug("intr ctl=%d vsync cnt=%u\n", ctl->num, ctl->vsync_cnt);
 
 	complete_all(&ctx->vsync_comp);
 	spin_lock(&ctx->vsync_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 2c0d5e0..2e20eb6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -88,18 +88,6 @@
 	HIST_READY,
 };
 
-struct pp_hist_col_info {
-	u32 col_state;
-	u32 col_en;
-	u32 read_request;
-	u32 hist_cnt_read;
-	u32 hist_cnt_sent;
-	u32 frame_cnt;
-	u32 is_kick_ready;
-	struct completion comp;
-	u32 data[HIST_V_SIZE];
-};
-
 static u32 dither_matrix[16] = {
 	15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10};
 static u32 dither_depth_map[9] = {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 969b400..2f77d29 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -118,10 +118,10 @@
 /* This needs to be modified manually now, when we add
  a new RANGE of SSIDs to the msg_mask_tbl */
 #define MSG_MASK_TBL_CNT		24
-#define EVENT_LAST_ID			0x09AB
+#define EVENT_LAST_ID			0x09B2
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			94
+#define MSG_SSID_0_LAST			97
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
@@ -287,6 +287,9 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
 	MSG_LVL_LOW
 };
 
@@ -722,7 +725,7 @@
 /* LOG CODES */
 
 #define LOG_0	0x0
-#define LOG_1	0x1755
+#define LOG_1	0x17F4
 #define LOG_2	0x0
 #define LOG_3	0x0
 #define LOG_4	0x4910
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 19face8..c2b35c8 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -108,7 +108,6 @@
 #define DMX_CHECK_CRC		0x01
 #define DMX_ONESHOT		0x02
 #define DMX_IMMEDIATE_START	0x04
-#define DMX_ENABLE_INDEXING	0x08
 #define DMX_KERNEL_CLIENT	0x8000
 
 struct dmx_sct_filter_params
@@ -120,25 +119,39 @@
 };
 
 
-/* Indexing: supported video standards */
-enum dmx_indexing_video_standard {
-	DMX_INDEXING_MPEG2,
-	DMX_INDEXING_H264,
-	DMX_INDEXING_VC1
+enum dmx_video_codec {
+	DMX_VIDEO_CODEC_MPEG2,
+	DMX_VIDEO_CODEC_H264,
+	DMX_VIDEO_CODEC_VC1
 };
 
-/* Indexing: Supported video profiles */
-enum dmx_indexing_video_profile {
-	DMX_INDEXING_MPEG2_ANY,
-	DMX_INDEXING_H264_ANY,
-	DMX_INDEXING_VC1_ANY
-};
-
-/* Indexing: video configuration parameters */
-struct dmx_indexing_video_params {
-	enum dmx_indexing_video_standard standard;
-	enum dmx_indexing_video_profile profile;
-};
+/* Index entries types */
+#define DMX_IDX_RAI                         0x00000001
+#define DMX_IDX_PUSI                        0x00000002
+#define DMX_IDX_MPEG_SEQ_HEADER             0x00000004
+#define DMX_IDX_MPEG_GOP                    0x00000008
+#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_START  0x00000010
+#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_END    0x00000020
+#define DMX_IDX_MPEG_I_FRAME_START          0x00000040
+#define DMX_IDX_MPEG_I_FRAME_END            0x00000080
+#define DMX_IDX_MPEG_P_FRAME_START          0x00000100
+#define DMX_IDX_MPEG_P_FRAME_END            0x00000200
+#define DMX_IDX_MPEG_B_FRAME_START          0x00000400
+#define DMX_IDX_MPEG_B_FRAME_END            0x00000800
+#define DMX_IDX_H264_SPS                    0x00001000
+#define DMX_IDX_H264_PPS                    0x00002000
+#define DMX_IDX_H264_FIRST_SPS_FRAME_START  0x00004000
+#define DMX_IDX_H264_FIRST_SPS_FRAME_END    0x00008000
+#define DMX_IDX_H264_IDR_START              0x00010000
+#define DMX_IDX_H264_IDR_END                0x00020000
+#define DMX_IDX_H264_NON_IDR_START          0x00040000
+#define DMX_IDX_H264_NON_IDR_END            0x00080000
+#define DMX_IDX_VC1_SEQ_HEADER              0x00100000
+#define DMX_IDX_VC1_ENTRY_POINT             0x00200000
+#define DMX_IDX_VC1_FIRST_SEQ_FRAME_START   0x00400000
+#define DMX_IDX_VC1_FIRST_SEQ_FRAME_END     0x00800000
+#define DMX_IDX_VC1_FRAME_START             0x01000000
+#define DMX_IDX_VC1_FRAME_END               0x02000000
 
 struct dmx_pes_filter_params
 {
@@ -160,7 +173,7 @@
 	 */
 	__u32          rec_chunk_size;
 
-	struct dmx_indexing_video_params video_params;
+	enum dmx_video_codec video_codec;
 };
 
 struct dmx_buffer_status {
@@ -213,7 +226,10 @@
 	DMX_EVENT_NEW_ES_DATA = 0x00000080,
 
 	/* Data markers */
-	DMX_EVENT_MARKER = 0x00000100
+	DMX_EVENT_MARKER = 0x00000100,
+
+	/* New indexing entry is ready */
+	DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200
 };
 
 enum dmx_oob_cmd {
@@ -377,6 +393,34 @@
 	__u64 id;
 };
 
+/* Indexing information associated with DMX_EVENT_NEW_INDEX_ENTRY event */
+struct dmx_index_event_info {
+	/* Index entry type, one of of DMX_IDX_* */
+	__u64 type;
+
+	/*
+	 * The PID the index entry belongs to.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl and each can be indexed seperatly.
+	 */
+	__u16 pid;
+
+	/*
+	 * The TS packet number in the recorded data at which
+	 * the indexing event is found.
+	 */
+	__u64 match_tsp_num;
+
+	/*
+	 * The TS packet number in the recorded data preceeding
+	 * match_tsp_num and has PUSI set.
+	 */
+	__u64 last_pusi_tsp_num;
+
+	/* STC associated with match_tsp_num, in 27MHz */
+	__u64 stc;
+};
+
 /*
  * Filter's event returned through DMX_GET_EVENT.
  * poll with POLLPRI would block until events are available.
@@ -391,6 +435,7 @@
 		struct dmx_pcr_event_info pcr;
 		struct dmx_es_data_event_info es_data;
 		struct dmx_marker_event_info marker;
+		struct dmx_index_event_info index;
 	} params;
 };
 
@@ -642,6 +687,22 @@
 	__u32 wakeup_threshold;
 };
 
+struct dmx_indexing_params {
+	/*
+	 * PID to index. In case of recording filter, multiple PIDs
+	 * may exist in the same filter through DMX_ADD_PID ioctl.
+	 * It is assumed that the PID was already added using DMX_ADD_PID
+	 * or an error will be reported.
+	 */
+	__u16 pid;
+
+	/* enable or disable indexing, default is disabled */
+	int enable;
+
+	/* combination of DMX_IDX_* bits */
+	__u64 types;
+};
+
 #define DMX_START                _IO('o', 41)
 #define DMX_STOP                 _IO('o', 42)
 #define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
@@ -669,5 +730,6 @@
 #define DMX_SET_EVENTS_MASK	_IOW('o', 66, struct dmx_events_mask)
 #define DMX_GET_EVENTS_MASK	_IOR('o', 67, struct dmx_events_mask)
 #define DMX_PUSH_OOB_COMMAND	_IOW('o', 68, struct dmx_oob_command)
+#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
 
 #endif /*_DVBDMX_H_*/
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index a87246c..3bb38ad 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -45,14 +45,14 @@
 	struct list_head next_chunk;	/* next chunk in pool */
 	atomic_t avail;
 	phys_addr_t phys_addr;		/* physical starting address of memory chunk */
-	unsigned long start_addr;	/* starting address of memory chunk */
-	unsigned long end_addr;		/* ending address of memory chunk */
+	u64 start_addr;			/* starting address of memory chunk */
+	u64 end_addr;			/* ending address of memory chunk */
 	unsigned long bits[0];		/* bitmap for allocating memory chunk */
 };
 
 extern struct gen_pool *gen_pool_create(int, int);
-extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
-extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
+extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, u64);
+extern int gen_pool_add_virt(struct gen_pool *, u64, phys_addr_t,
 			     size_t, int);
 /**
  * gen_pool_add - add a new chunk of special memory to the pool
@@ -66,19 +66,19 @@
  *
  * Returns 0 on success or a -ve errno on failure.
  */
-static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
+static inline int gen_pool_add(struct gen_pool *pool, u64 addr,
 			       size_t size, int nid)
 {
 	return gen_pool_add_virt(pool, addr, -1, size, nid);
 }
 extern void gen_pool_destroy(struct gen_pool *);
-extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
+extern void gen_pool_free(struct gen_pool *, u64, size_t);
 extern void gen_pool_for_each_chunk(struct gen_pool *,
 	void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
 extern size_t gen_pool_avail(struct gen_pool *);
 extern size_t gen_pool_size(struct gen_pool *);
 
-unsigned long __must_check
+u64 __must_check
 gen_pool_alloc_aligned(struct gen_pool *pool, size_t size,
                        unsigned alignment_order);
 
@@ -90,7 +90,7 @@
  * Allocate the requested number of bytes from the specified pool.
  * Uses a first-fit algorithm.
  */
-static inline unsigned long __must_check
+static inline u64 __must_check
 gen_pool_alloc(struct gen_pool *pool, size_t size)
 {
         return gen_pool_alloc_aligned(pool, size, 0);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3b5742e..9eef3a0 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -454,6 +454,12 @@
 
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
+	if (!host->sdio_irqs) {
+		pr_err("%s: SDIO interrupt recieved without function driver claiming an irq\n",
+				mmc_hostname(host));
+		return;
+	}
+
 	host->ops->enable_sdio_irq(host, 0);
 	host->sdio_irq_pending = true;
 	wake_up_process(host->sdio_irq_thread);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 407a005..538185f 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -208,6 +208,7 @@
 	struct pm_qos_request pm_qos_req_dma;
 
 	struct sdhci_next next_data;
+	ktime_t data_start_time;
 
 	unsigned long private[0] ____cacheline_aligned;
 };
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 396fcd8..20b7317 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -9,6 +9,7 @@
 	ION_HEAP_TYPE_DMA,
 	ION_HEAP_TYPE_CP,
 	ION_HEAP_TYPE_SECURE_DMA,
+	ION_HEAP_TYPE_REMOVED,
 };
 
 /**
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 7e1a709..60567fa 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -289,14 +289,19 @@
 #define MDP_PP_IGC_FLAG_ROM0	0x10
 #define MDP_PP_IGC_FLAG_ROM1	0x20
 
-#define MDSS_PP_DSPP_CFG	0x0000
-#define MDSS_PP_SSPP_CFG	0x4000
-#define MDSS_PP_LM_CFG	0x8000
-#define MDSS_PP_WB_CFG	0xC000
+#define MDSS_PP_DSPP_CFG	0x000
+#define MDSS_PP_SSPP_CFG	0x100
+#define MDSS_PP_LM_CFG	0x200
+#define MDSS_PP_WB_CFG	0x300
 
-#define MDSS_PP_LOCATION_MASK	0xC000
-#define MDSS_PP_LOGICAL_MASK	0x3FFF
+#define MDSS_PP_ARG_MASK	0x3C00
+#define MDSS_PP_ARG_NUM		4
+#define MDSS_PP_ARG_SHIFT	8
+#define MDSS_PP_LOCATION_MASK	0x0300
+#define MDSS_PP_LOGICAL_MASK	0x00FF
 
+#define MDSS_PP_ADD_ARG(var, arg) ((var) | (0x1 << (MDSS_PP_ARG_SHIFT + (arg))))
+#define PP_ARG(x, var) ((var) & (0x1 << (MDSS_PP_ARG_SHIFT + (x))))
 #define PP_LOCAT(var) ((var) & MDSS_PP_LOCATION_MASK)
 #define PP_BLOCK(var) ((var) & MDSS_PP_LOGICAL_MASK)
 
@@ -326,6 +331,7 @@
 #define MDP_OVERLAY_PP_PA_CFG          0x4
 #define MDP_OVERLAY_PP_IGC_CFG         0x8
 #define MDP_OVERLAY_PP_SHARP_CFG       0x10
+#define MDP_OVERLAY_PP_HIST_CFG        0x20
 
 #define MDP_CSC_FLAG_ENABLE	0x1
 #define MDP_CSC_FLAG_YUV_IN	0x2
@@ -361,6 +367,14 @@
 	uint32_t *c2_data;
 };
 
+struct mdp_histogram_cfg {
+	uint32_t ops;
+	uint32_t block;
+	uint8_t frame_cnt;
+	uint8_t bit_mask;
+	uint16_t num_bins;
+};
+
 struct mdp_overlay_pp_params {
 	uint32_t config_ops;
 	struct mdp_csc_cfg csc_cfg;
@@ -368,6 +382,7 @@
 	struct mdp_pa_cfg pa_cfg;
 	struct mdp_igc_lut_data igc_cfg;
 	struct mdp_sharp_cfg sharp_cfg;
+	struct mdp_histogram_cfg hist_cfg;
 };
 
 struct mdp_overlay {
@@ -433,7 +448,7 @@
 	MDP_BLOCK_DMA_S,
 	MDP_BLOCK_DMA_E,
 	MDP_BLOCK_OVERLAY_2,
-	MDP_LOGICAL_BLOCK_DISP_0 = 0x1000,
+	MDP_LOGICAL_BLOCK_DISP_0 = 0x10,
 	MDP_LOGICAL_BLOCK_DISP_1,
 	MDP_LOGICAL_BLOCK_DISP_2,
 	MDP_BLOCK_MAX,
@@ -552,6 +567,65 @@
 	uint32_t data;
 };
 
+#define MDSS_AD_MODE_AUTO_BL	0x0
+#define MDSS_AD_MODE_AUTO_STR	0x1
+#define MDSS_AD_MODE_TARG_STR	0x3
+#define MDSS_AD_MODE_MAN_STR	0x7
+
+#define MDP_PP_AD_INIT	0x10
+#define MDP_PP_AD_CFG	0x20
+
+struct mdss_ad_init {
+	uint32_t asym_lut[33];
+	uint32_t color_corr_lut[33];
+	uint8_t i_control[2];
+	uint16_t black_lvl;
+	uint16_t white_lvl;
+	uint8_t var;
+	uint8_t limit_ampl;
+	uint8_t i_dither;
+	uint8_t slope_max;
+	uint8_t slope_min;
+	uint8_t dither_ctl;
+	uint8_t format;
+	uint8_t auto_size;
+	uint16_t frame_w;
+	uint16_t frame_h;
+	uint8_t logo_v;
+	uint8_t logo_h;
+};
+
+struct mdss_ad_cfg {
+	uint32_t mode;
+	uint32_t al_calib_lut[33];
+	uint16_t backlight_min;
+	uint16_t backlight_max;
+	uint16_t backlight_scale;
+	uint16_t amb_light_min;
+	uint16_t filter[2];
+	uint16_t calib[4];
+	uint8_t strength_limit;
+	uint8_t t_filter_recursion;
+};
+
+/* ops uses standard MDP_PP_* flags */
+struct mdss_ad_init_cfg {
+	uint32_t ops;
+	union {
+		struct mdss_ad_init init;
+		struct mdss_ad_cfg cfg;
+	} params;
+};
+
+/* mode uses MDSS_AD_MODE_* flags */
+struct mdss_ad_input {
+	uint32_t mode;
+	union {
+		uint32_t amb_light;
+		uint32_t strength;
+	} in;
+};
+
 enum {
 	mdp_op_pcc_cfg,
 	mdp_op_csc_cfg,
@@ -562,6 +636,8 @@
 	mdp_op_dither_cfg,
 	mdp_op_gamut_cfg,
 	mdp_op_calib_cfg,
+	mdp_op_ad_cfg,
+	mdp_op_ad_input,
 	mdp_op_max,
 };
 
@@ -586,6 +662,8 @@
 		struct mdp_dither_cfg_data dither_cfg_data;
 		struct mdp_gamut_cfg_data gamut_cfg_data;
 		struct mdp_calib_config_data calib_cfg;
+		struct mdss_ad_init_cfg ad_init_cfg;
+		struct mdss_ad_input ad_input;
 	} data;
 };
 
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2c9a613..f14cc52 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,9 +17,16 @@
 struct msm_thermal_data {
 	uint32_t sensor_id;
 	uint32_t poll_ms;
-	uint32_t limit_temp_degC;
-	uint32_t temp_hysteresis_degC;
+	int32_t limit_temp_degC;
+	int32_t temp_hysteresis_degC;
 	uint32_t freq_step;
+	int32_t core_limit_temp_degC;
+	int32_t core_temp_hysteresis_degC;
+	uint32_t core_control_mask;
+	int32_t vdd_rstr_temp_degC;
+	int32_t vdd_rstr_temp_hyst_degC;
+	int32_t psm_temp_degC;
+	int32_t psm_temp_hyst_degC;
 };
 
 #ifdef CONFIG_THERMAL_MONITOR
diff --git a/include/linux/msm_tsens.h b/include/linux/msm_tsens.h
index 8aa7c17..757f1dc 100644
--- a/include/linux/msm_tsens.h
+++ b/include/linux/msm_tsens.h
@@ -41,6 +41,14 @@
 
 int32_t tsens_get_temp(struct tsens_device *dev, unsigned long *temp);
 int msm_tsens_early_init(struct tsens_platform_data *pdata);
+
+#if defined(CONFIG_THERMAL_TSENS8974)
+int __init tsens_tm_init_driver(void);
+#else
+static inline int __init tsens_tm_init_driver(void)
+{ return -ENXIO; }
+#endif
+
 #if defined(CONFIG_THERMAL_TSENS8974) || defined(CONFIG_THERMAL_TSENS8960)
 int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors);
 #else
diff --git a/include/linux/smsc3503.h b/include/linux/smsc3503.h
index d5df871..1e28a58 100644
--- a/include/linux/smsc3503.h
+++ b/include/linux/smsc3503.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 software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -42,9 +42,9 @@
 #define OCSPINSEL	(1<<5)
 
 struct smsc_hub_platform_data {
-	unsigned hub_reset;
-	unsigned refclk_gpio;
-	unsigned int_gpio;
+	int hub_reset;
+	int refclk_gpio;
+	int int_gpio;
 };
 
 #endif
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 9cf1b8b..604ee09 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -171,7 +171,7 @@
  *
  * Returns 0 on success or a -ve errno on failure.
  */
-int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
+int gen_pool_add_virt(struct gen_pool *pool, u64 virt, phys_addr_t phys,
 		 size_t size, int nid)
 {
 	struct gen_pool_chunk *chunk;
@@ -208,7 +208,7 @@
  *
  * Returns the physical address on success, or -1 on error.
  */
-phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
+phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, u64 addr)
 {
 	struct gen_pool_chunk *chunk;
 	phys_addr_t paddr = -1;
@@ -273,11 +273,11 @@
  * Uses a first-fit algorithm. Can not be used in NMI handler on
  * architectures without NMI-safe cmpxchg implementation.
  */
-unsigned long gen_pool_alloc_aligned(struct gen_pool *pool, size_t size,
+u64 gen_pool_alloc_aligned(struct gen_pool *pool, size_t size,
 				     unsigned alignment_order)
 {
 	struct gen_pool_chunk *chunk;
-	unsigned long addr = 0, align_mask = 0;
+	u64 addr = 0, align_mask = 0;
 	int order = pool->min_alloc_order;
 	int nbits, start_bit = 0, remain;
 
@@ -314,7 +314,7 @@
 			goto retry;
 		}
 
-		addr = chunk->start_addr + ((unsigned long)start_bit << order);
+		addr = chunk->start_addr + ((u64)start_bit << order);
 		size = nbits << pool->min_alloc_order;
 		atomic_sub(size, &chunk->avail);
 		break;
@@ -334,7 +334,7 @@
  * pool.  Can not be used in NMI handler on architectures without
  * NMI-safe cmpxchg implementation.
  */
-void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
+void gen_pool_free(struct gen_pool *pool, u64 addr, size_t size)
 {
 	struct gen_pool_chunk *chunk;
 	int order = pool->min_alloc_order;
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 866f524..f5f4e23 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -102,6 +102,12 @@
 #define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
 #define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
 
+#define CUT_OF_FREQ_MASK 0x30
+#define CF_MIN_3DB_4HZ 0x0
+#define CF_MIN_3DB_75HZ 0x01
+#define CF_MIN_3DB_150HZ 0x02
+
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -194,6 +200,15 @@
 	0,					/* AIF1_CAP */
 };
 
+struct hpf_work {
+	struct sitar_priv *sitar;
+	u32 decimator;
+	u8 tx_hpf_cut_of_freq;
+	struct delayed_work dwork;
+};
+
+static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
 struct sitar_priv {
 	struct snd_soc_codec *codec;
 	u32 mclk_freq;
@@ -1755,6 +1770,8 @@
 			snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+
+		usleep_range(20000, 20000);
 		if (sitar->mbhc_polling_active &&
 		    sitar->mbhc_cfg.micbias == micb_line) {
 			SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
@@ -1780,36 +1797,141 @@
 	return 0;
 }
 
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct sitar_priv *sitar;
+	struct snd_soc_codec *codec;
+	u16 tx_mux_ctl_reg;
+	u8 hpf_cut_of_freq;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	sitar = hpf_work->sitar;
+	codec = hpf_work->sitar->codec;
+	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL +
+				(hpf_work->decimator - 1) * 8;
+
+	pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
+			hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg,
+			CUT_OF_FREQ_MASK, hpf_cut_of_freq << 4);
+}
+
 static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 dec_reset_reg, gain_reg;
-	u8 current_gain;
+	u16 dec_reset_reg, gain_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+	unsigned int decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	int ret = 0;
+	u8 dec_hpf_cut_of_freq, current_gain;
 
 	pr_debug("%s %d\n", __func__, event);
 
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
+	if (ret < 0) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+		w->name, dec_name, decimator);
+
 	if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
 		dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
 	else {
 		pr_err("%s: Error, incorrect dec\n", __func__);
-		return -EINVAL;
+		ret = EINVAL;
+		goto out;
 	}
 
+	tx_vol_ctl_reg = SITAR_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
+	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable TX Digital Mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+
 		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
 			1 << w->shift);
 		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+
+		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+		dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq &
+						CUT_OF_FREQ_MASK) >> 4;
+
+		tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+						dec_hpf_cut_of_freq;
+
+		if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
+			/* Set cut off freq to CF_MIN_3DB_150HZ (0x01) */
+			snd_soc_update_bits(codec, tx_mux_ctl_reg,
+				CUT_OF_FREQ_MASK, CF_MIN_3DB_150HZ << 4);
+		}
+
+		/* enable HPF */
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
+
 		break;
+
 	case SND_SOC_DAPM_POST_PMU:
+		/* Disable TX Digital Mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+
+		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+				CF_MIN_3DB_150HZ) {
+			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+				msecs_to_jiffies(300));
+		}
+
 		/* Reprogram the digital gain after power up of Decimator */
 		gain_reg = SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * w->shift);
 		current_gain = snd_soc_read(codec, gain_reg);
 		snd_soc_write(codec, gain_reg, current_gain);
 		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Enable Digital Mute, Cancel possibly scheduled work */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, CUT_OF_FREQ_MASK,
+			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+		break;
+
 	}
-	return 0;
+
+out:
+	kfree(widget_name);
+	return ret;
+
 }
 
 static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
@@ -2278,16 +2400,23 @@
 
 	SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
 		&dec1_mux, sitar_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
 		&dec2_mux, sitar_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
 		&dec3_mux, sitar_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
 		&dec4_mux, sitar_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
 	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
@@ -5316,6 +5445,14 @@
 		return -ENOMEM;
 	}
 
+	for (i = 0; i < NUM_DECIMATORS; i++) {
+		tx_hpf_work[i].sitar = sitar;
+		tx_hpf_work[i].decimator = i + 1;
+		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+						  tx_hpf_corner_freq_callback);
+	}
+
+
 	/* Make sure mbhc micbias register addresses are zeroed out */
 	memset(&sitar->mbhc_bias_regs, 0,
 		sizeof(struct mbhc_micbias_regs));
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index fd3e0dc..a7069a6 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -193,6 +193,7 @@
 	s32 dmic_5_6_clk_cnt;
 
 	u32 anc_slot;
+	bool anc_func;
 
 	/*track tapan interface type*/
 	u8 intf_type;
@@ -348,6 +349,58 @@
 	return 0;
 }
 
+static int tapan_get_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = (tapan->anc_func == true ? 1 : 0);
+	return 0;
+}
+
+static int tapan_put_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	mutex_lock(&dapm->codec->mutex);
+	tapan->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+
+	dev_err(codec->dev, "%s: anc_func %x", __func__, tapan->anc_func);
+
+	if (tapan->anc_func == true) {
+		pr_info("enable anc virtual widgets");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC EAR");
+		snd_soc_dapm_disable_pin(dapm, "HPHR");
+		snd_soc_dapm_disable_pin(dapm, "HPHL");
+		snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
+		snd_soc_dapm_disable_pin(dapm, "EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "EAR");
+	} else {
+		pr_info("disable anc virtual widgets");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+		snd_soc_dapm_enable_pin(dapm, "HPHR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL");
+		snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
+		snd_soc_dapm_enable_pin(dapm, "EAR PA");
+		snd_soc_dapm_enable_pin(dapm, "EAR");
+	}
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
+	return 0;
+}
+
 static int tapan_pa_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -713,6 +766,10 @@
 		SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
 };
 
+static const char *const tapan_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tapan_anc_func_enum =
+		SOC_ENUM_SINGLE_EXT(2, tapan_anc_func_text);
+
 /*cut of frequency for high pass filter*/
 static const char * const cf_text[] = {
 	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
@@ -770,11 +827,11 @@
 	SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
 		line_gain),
 
-	SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 13, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 13, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 13, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 13, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 13, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 19, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 19, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 19, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 19, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
 
 	SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
@@ -803,9 +860,10 @@
 	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
 		40, digital_gain),
 
-	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tapan_get_anc_slot,
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
 		tapan_put_anc_slot),
-
+	SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
+		tapan_put_anc_func),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -943,6 +1001,10 @@
 	"RSVD", "RSVD"
 };
 
+static const char * const anc1_fb_mux_text[] = {
+	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
+};
+
 static const char * const iir1_inp1_text[] = {
 	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
 	"RX1", "RX2", "RX3", "RX4", "RX5"
@@ -1031,6 +1093,9 @@
 static const struct soc_enum anc2_mux_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
 
+static const struct soc_enum anc1_fb_mux_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
+
 static const struct soc_enum iir1_inp1_mux_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
 
@@ -1200,6 +1265,9 @@
 static const struct snd_kcontrol_new anc2_mux =
 	SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
 
+static const struct snd_kcontrol_new anc1_fb_mux =
+	SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
 static const struct snd_kcontrol_new dac1_switch[] = {
 	SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
 };
@@ -1322,11 +1390,11 @@
 			return 0;
 		}
 		break;
-		default:
-			dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
-			mutex_unlock(&codec->mutex);
-			return -EINVAL;
-		}
+	default:
+		dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
+		mutex_unlock(&codec->mutex);
+		return -EINVAL;
+	}
 	dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
 		 __func__, widget->name, widget->sname,
 		 widget->value, widget->shift);
@@ -1392,14 +1460,14 @@
 	break;
 	case 2:
 		if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
-			&tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
+			&tapan_p->dai[AIF2_PB].wcd9xxx_ch_list))
 			goto pr_err;
 		list_add_tail(&core->rx_chs[port_id].list,
 			      &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
 	break;
 	case 3:
 		if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
-			&tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
+			&tapan_p->dai[AIF3_PB].wcd9xxx_ch_list))
 			goto pr_err;
 		list_add_tail(&core->rx_chs[port_id].list,
 			      &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
@@ -1668,9 +1736,11 @@
 	int anc_size_remaining;
 	u32 *anc_ptr;
 	u16 reg;
-	u8 mask, val;
+	u8 mask, val, old_val;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+	if (tapan->anc_func == 0)
+		return 0;
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 
@@ -1737,14 +1807,21 @@
 		for (i = 0; i < anc_writes_size; i++) {
 			TAPAN_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
 				mask, val);
-			snd_soc_write(codec, reg, val);
+			old_val = snd_soc_read(codec, reg);
+			snd_soc_write(codec, reg, (old_val & ~mask) |
+					(val & mask));
 		}
 		release_firmware(fw);
 
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+		msleep(40);
+		snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
+		msleep(20);
+		snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
 		snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+		snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
 		break;
 	}
 	return 0;
@@ -2137,12 +2214,12 @@
 
 	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
 	if (w->shift == 5) {
-		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
-		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
-		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
-	} else if (w->shift == 4) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
+	} else if (w->shift == 4) {
+		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
+		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
 		req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
 	} else {
 		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
@@ -2182,6 +2259,46 @@
 	return 0;
 }
 
+static int tapan_codec_enable_anc_hph(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = tapan_hph_pa_event(w, kcontrol, event);
+		if (w->shift == 4) {
+			ret |= tapan_codec_enable_anc(w, kcontrol, event);
+			msleep(50);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->shift == 4) {
+			snd_soc_update_bits(codec,
+					TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x30);
+			msleep(30);
+		}
+		ret = tapan_hph_pa_event(w, kcontrol, event);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (w->shift == 5) {
+			snd_soc_update_bits(codec,
+					TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
+			msleep(40);
+		}
+		if (w->shift == 5) {
+			snd_soc_update_bits(codec,
+					TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
+			ret |= tapan_codec_enable_anc(w, kcontrol, event);
+		}
+	case SND_SOC_DAPM_POST_PMD:
+		ret = tapan_hph_pa_event(w, kcontrol, event);
+		break;
+	}
+	return ret;
+}
+
 static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
 	4, 0, NULL, 0),
@@ -2296,6 +2413,11 @@
 	{"EAR_PA_MIXER", NULL, "DAC1"},
 	{"DAC1", NULL, "RX_BIAS"},
 
+	{"ANC EAR", NULL, "ANC EAR PA"},
+	{"ANC EAR PA", NULL, "EAR_PA_MIXER"},
+	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
+	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
+
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
@@ -2308,6 +2430,33 @@
 	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
 	{"HPHR DAC", NULL, "RX_BIAS"},
 
+	{"ANC HEADPHONE", NULL, "ANC HPHL"},
+	{"ANC HEADPHONE", NULL, "ANC HPHR"},
+
+	{"ANC HPHL", NULL, "HPHL_PA_MIXER"},
+	{"ANC HPHR", NULL, "HPHR_PA_MIXER"},
+
+	{"ANC1 MUX", "ADC1", "ADC1"},
+	{"ANC1 MUX", "ADC2", "ADC2"},
+	{"ANC1 MUX", "ADC3", "ADC3"},
+	{"ANC1 MUX", "ADC4", "ADC4"},
+	{"ANC1 MUX", "ADC5", "ADC5"},
+	{"ANC1 MUX", "DMIC1", "DMIC1"},
+	{"ANC1 MUX", "DMIC2", "DMIC2"},
+	{"ANC1 MUX", "DMIC3", "DMIC3"},
+	{"ANC1 MUX", "DMIC4", "DMIC4"},
+	{"ANC2 MUX", "ADC1", "ADC1"},
+	{"ANC2 MUX", "ADC2", "ADC2"},
+	{"ANC2 MUX", "ADC3", "ADC3"},
+	{"ANC2 MUX", "ADC4", "ADC4"},
+	{"ANC2 MUX", "ADC5", "ADC5"},
+	{"ANC2 MUX", "DMIC1", "DMIC1"},
+	{"ANC2 MUX", "DMIC2", "DMIC2"},
+	{"ANC2 MUX", "DMIC3", "DMIC3"},
+	{"ANC2 MUX", "DMIC4", "DMIC4"},
+
+	{"ANC HPHR", NULL, "CDC_CONN"},
+
 	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -2336,6 +2485,8 @@
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
 	{"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
+	{"RX1 MIX2", NULL, "ANC1 MUX"},
+	{"RX2 MIX2", NULL, "ANC2 MUX"},
 
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
@@ -2564,6 +2715,14 @@
 		(reg <= TAPAN_A_CDC_IIR2_COEF_B2_CTL))
 		return 1;
 
+	/* ANC filter registers are not cacheable */
+	if ((reg >= TAPAN_A_CDC_ANC1_IIR_B1_CTL) &&
+		(reg <= TAPAN_A_CDC_ANC1_LPF_B2_CTL))
+		return 1;
+	if ((reg >= TAPAN_A_CDC_ANC2_IIR_B1_CTL) &&
+		(reg <= TAPAN_A_CDC_ANC2_LPF_B2_CTL))
+		return 1;
+
 	/* Digital gain register is not cacheable so we have to write
 	 * the setting even it is the same
 	 */
@@ -2850,7 +3009,7 @@
 					tapan->comp_fs[comp_rx_path[j]]
 					= compander_fs;
 			}
-			if (j <= 2)
+			if (j <= 1)
 				rx_mix_1_reg_1 += 3;
 			else
 				rx_mix_1_reg_1 += 2;
@@ -3419,6 +3578,33 @@
 	return 0;
 }
 
+static int tapan_codec_enable_anc_ear(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = tapan_codec_enable_anc(w, kcontrol, event);
+		msleep(50);
+		snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x00);
+		msleep(40);
+		ret |= tapan_codec_enable_anc(w, kcontrol, event);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
+		break;
+	}
+	return ret;
+}
+
 
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
@@ -3695,9 +3881,21 @@
 	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
 	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
 
-	SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
-		tapan_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
+		tapan_codec_enable_anc_hph,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
+		tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("ANC EAR"),
+	SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tapan_codec_enable_anc_ear,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
 
 	SND_SOC_DAPM_INPUT("AMIC2"),
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
@@ -4304,6 +4502,14 @@
 	(void) tapan_setup_irqs(tapan);
 
 	atomic_set(&kp_tapan_priv, (unsigned long)tapan);
+	mutex_lock(&dapm->codec->mutex);
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+	snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+	snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
 
 	codec->ignore_pmdown_time = 1;
 	return ret;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index c5cb560..e74a0dd 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -93,6 +93,7 @@
 static const DECLARE_TLV_DB_LINEAR(compressed3_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
 static int msm_route_ec_ref_rx;
+static int msm_route_ext_ec_ref;
 
 /* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
 #define MAX_EQ_SESSIONS		MSM_FRONTEND_DAI_CS_VOICE
@@ -1425,6 +1426,57 @@
 	msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
 };
 
+static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: ext_ec_ref_rx  = %x\n", __func__, msm_route_ext_ec_ref);
+
+	mutex_lock(&routing_lock);
+	ucontrol->value.integer.value[0] = msm_route_ext_ec_ref;
+	mutex_unlock(&routing_lock);
+	return 0;
+}
+
+static int msm_routing_ext_ec_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	int mux = ucontrol->value.enumerated.item[0];
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int ret = 0;
+
+	pr_debug("%s: msm_route_ec_ref_rx = %d value = %ld\n",
+		 __func__, msm_route_ext_ec_ref,
+		 ucontrol->value.integer.value[0]);
+
+	mutex_lock(&routing_lock);
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		msm_route_ext_ec_ref = MI2S_TX;
+		ret = voc_set_ext_ec_ref(msm_route_ext_ec_ref, true);
+		break;
+	default:
+		msm_route_ext_ec_ref = AFE_PORT_INVALID;
+		ret = voc_set_ext_ec_ref(msm_route_ext_ec_ref, false);
+		break;
+	}
+	snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static const char * const ext_ec_ref_rx[] = {"NONE", "MI2S_TX"};
+
+static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, ext_ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new voc_ext_ec_mux =
+	SOC_DAPM_ENUM_EXT("VOC_EXT_EC MUX Mux", msm_route_ext_ec_ref_rx_enum[0],
+			  msm_routing_ext_ec_get, msm_routing_ext_ec_put);
+
+
 static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -2887,6 +2939,7 @@
 	/* Virtual Pins to force backends ON atm */
 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
 	SND_SOC_DAPM_INPUT("BE_IN"),
+	SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0, &voc_ext_ec_mux),
 
 };
 
@@ -3071,6 +3124,8 @@
 	{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
 	{"HDMI", NULL, "HDMI_DL_HL"},
 
+	{"VOC_EXT_EC MUX", "MI2S_TX" , "MI2S_TX"},
+	{"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
 	{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
 	{"Voice_Tx Mixer", "SEC_TX_Voice", "SEC_I2S_TX"},
 	{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 17f2d03..bb13695 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -73,6 +73,7 @@
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv);
 static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
 static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
+static int voice_send_set_device_cmd_v2(struct voice_data *v);
 
 static u16 voice_get_mvm_handle(struct voice_data *v)
 {
@@ -1380,6 +1381,80 @@
 	return -EINVAL;
 }
 
+static int voice_send_set_device_cmd_v2(struct voice_data *v)
+{
+	struct cvp_set_device_cmd_v2  cvp_setdev_cmd_v2;
+	int ret = 0;
+	void *apr_cvp;
+	u16 cvp_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = common.apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvp_handle = voice_get_cvp_handle(v);
+
+	/* set device and wait for response */
+	cvp_setdev_cmd_v2.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_setdev_cmd_v2.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_setdev_cmd_v2) - APR_HDR_SIZE);
+	cvp_setdev_cmd_v2.hdr.src_port = v->session_id;
+	cvp_setdev_cmd_v2.hdr.dest_port = cvp_handle;
+	cvp_setdev_cmd_v2.hdr.token = 0;
+	cvp_setdev_cmd_v2.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE_V2;
+
+	voc_get_tx_rx_topology(v,
+			&cvp_setdev_cmd_v2.cvp_set_device_v2.tx_topology_id,
+			&cvp_setdev_cmd_v2.cvp_set_device_v2.rx_topology_id);
+
+	cvp_setdev_cmd_v2.cvp_set_device_v2.tx_port_id = v->dev_tx.port_id;
+	cvp_setdev_cmd_v2.cvp_set_device_v2.rx_port_id = v->dev_rx.port_id;
+	if (common.ec_ref_ext == true) {
+		cvp_setdev_cmd_v2.cvp_set_device_v2.vocproc_mode =
+				VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+		cvp_setdev_cmd_v2.cvp_set_device_v2.ec_ref_port_id =
+				common.ec_port_id;
+	} else {
+		cvp_setdev_cmd_v2.cvp_set_device_v2.vocproc_mode =
+				VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+		cvp_setdev_cmd_v2.cvp_set_device_v2.ec_ref_port_id =
+				VSS_IVOCPROC_PORT_ID_NONE;
+	}
+	pr_debug("%s:topology=%d , tx_port_id=%d, rx_port_id=%d\n"
+		 "ec_ref_port_id = %x\n", __func__,
+		 cvp_setdev_cmd_v2.cvp_set_device_v2.tx_topology_id,
+		 cvp_setdev_cmd_v2.cvp_set_device_v2.tx_port_id,
+		 cvp_setdev_cmd_v2.cvp_set_device_v2.rx_port_id,
+		 cvp_setdev_cmd_v2.cvp_set_device_v2.ec_ref_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd_v2);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+		goto fail;
+	}
+	pr_debug("wait for cvp create session event\n");
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
 static int voice_send_stop_voice_cmd(struct voice_data *v)
 {
 	struct apr_hdr mvm_stop_voice_cmd;
@@ -2277,7 +2352,13 @@
 		pr_err("%s: wait_event timeout\n", __func__);
 		goto fail;
 	}
-
+	if (common.ec_ref_ext == true) {
+		ret = voice_send_set_device_cmd_v2(v);
+		if (ret < 0)
+			pr_err("%s:  set device V2 failed rc =%x\n",
+			       __func__, ret);
+			goto fail;
+	}
 	/* send cvs cal */
 	ret = voice_send_cvs_map_memory_cmd(v);
 	if (!ret)
@@ -3242,7 +3323,8 @@
 		voice_send_cvp_deregister_cal_cmd(v);
 		voice_get_cal_paddr_size(v, &paddr, NULL);
 		voice_send_cvp_unmap_memory_cmd(v, paddr);
-
+		if (common.ec_ref_ext == true)
+			voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
 		v->voc_state = VOC_CHANGE;
 	}
 
@@ -3268,10 +3350,19 @@
 	mutex_lock(&v->lock);
 
 	if (v->voc_state == VOC_CHANGE) {
-		ret = voice_send_set_device_cmd(v);
-		if (ret < 0) {
-			pr_err("%s:  set device failed\n", __func__);
-			goto fail;
+		if (common.ec_ref_ext == true) {
+			ret = voice_send_set_device_cmd_v2(v);
+			if (ret < 0)
+				pr_err("%s: set device V2 failed\n"
+				       "rc =%x\n", __func__, ret);
+				goto fail;
+		} else {
+			ret = voice_send_set_device_cmd(v);
+			if (ret < 0) {
+				pr_err("%s: set device failed rc=%x\n",
+				       __func__, ret);
+				goto fail;
+			}
 		}
 		/* send cvp and vol cal */
 		if (!voice_get_cal_paddr_size(v, &cal_paddr, &cal_size) &&
@@ -3675,7 +3766,8 @@
 		if (ret < 0)
 			pr_err("%s:  destroy voice failed\n", __func__);
 		voice_destroy_mvm_cvs_session(v);
-
+		if (common.ec_ref_ext == true)
+			voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
 		v->voc_state = VOC_RELEASE;
 	}
 	mutex_unlock(&v->lock);
@@ -3845,6 +3937,28 @@
 	return ret;
 }
 
+int voc_set_ext_ec_ref(uint16_t port_id, bool state)
+{
+	int ret = 0;
+
+	mutex_lock(&common.common_lock);
+	if (state == true) {
+		if (port_id == AFE_PORT_INVALID) {
+			pr_err("%s: Invalid port id", __func__);
+			ret = -EINVAL;
+			goto fail;
+		}
+		common.ec_port_id = port_id;
+		common.ec_ref_ext = true;
+	} else {
+		common.ec_ref_ext = false;
+		common.ec_port_id = port_id;
+	}
+fail:
+	mutex_unlock(&common.common_lock);
+	return ret;
+}
+
 void voc_register_mvs_cb(ul_cb_fn ul_cb,
 			   dl_cb_fn dl_cb,
 			   void *private_data)
@@ -4201,6 +4315,7 @@
 				v->cvp_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->cvp_wait);
 				break;
+			case VSS_IVOCPROC_CMD_SET_DEVICE_V2:
 			case VSS_IVOCPROC_CMD_SET_DEVICE:
 			case VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX:
 			case VSS_IVOCPROC_CMD_ENABLE:
@@ -4517,6 +4632,7 @@
 	common.default_mute_val = 0;  /* default is un-mute */
 	common.default_vol_val = 0;
 	common.default_sample_val = 8000;
+	common.ec_ref_ext = false;
 
 	/* Initialize MVS info. */
 	common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 0bae384..7463a5f 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -903,6 +903,8 @@
 
 #define VSS_IVOCPROC_CMD_SET_DEVICE			0x000100C4
 
+#define VSS_IVOCPROC_CMD_SET_DEVICE_V2			0x000112C6
+
 #define VSS_IVOCPROC_CMD_SET_VP3_DATA			0x000110EB
 
 #define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX		0x000110EE
@@ -958,6 +960,9 @@
 #define VOICE_CMD_GET_PARAM				0x00011007
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
 
+/* Default AFE port ID. Applicable to Tx and Rx. */
+#define VSS_IVOCPROC_PORT_ID_NONE			0xFFFF
+
 struct vss_ivocproc_cmd_create_full_control_session_t {
 	uint16_t direction;
 	/*
@@ -1027,6 +1032,32 @@
 	*/
 } __packed;
 
+/* Internal EC */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING 0x00010F7C
+
+/* External EC */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING 0x00010F7D
+
+struct vss_ivocproc_cmd_set_device_v2_t {
+	uint16_t tx_port_id;
+	/* Tx device port ID to which the vocproc connects. */
+	uint32_t tx_topology_id;
+	/* Tx path topology ID. */
+	uint16_t rx_port_id;
+	/* Rx device port ID to which the vocproc connects. */
+	uint32_t rx_topology_id;
+	/* Rx path topology ID. */
+	uint32_t vocproc_mode;
+	/* Vocproc mode. The supported values:
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING - 0x00010F7C
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING - 0x00010F7D
+	 */
+	uint16_t ec_ref_port_id;
+	/* Port ID to which the vocproc connects for receiving
+	 * echo cancellation reference signal.
+	 */
+} __packed;
+
 struct vss_ivocproc_cmd_register_calibration_data_t {
 	uint32_t phys_addr;
 	/* Phsical address to be registered with vocproc. Calibration data
@@ -1076,6 +1107,11 @@
 	struct vss_ivocproc_cmd_set_device_t cvp_set_device;
 } __packed;
 
+struct cvp_set_device_cmd_v2 {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_set_device_v2_t cvp_set_device_v2;
+} __packed;
+
 struct cvp_set_vp3_data_cmd {
 	struct apr_hdr hdr;
 } __packed;
@@ -1227,6 +1263,8 @@
 	uint32_t default_mute_val;
 	uint32_t default_vol_val;
 	uint32_t default_sample_val;
+	bool ec_ref_ext;
+	uint16_t ec_port_id;
 
 	/* APR to MVM in the Q6 */
 	void *apr_q6_mvm;
@@ -1325,4 +1363,5 @@
 
 int voc_start_playback(uint32_t set);
 int voc_start_record(uint32_t port_id, uint32_t set);
+int voc_set_ext_ec_ref(uint16_t port_id, bool state);
 #endif
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index c14cb74..ad96ae3 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -20,18 +20,58 @@
 #include <linux/platform_device.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <linux/of_device.h>
+#include <linux/memory_alloc.h>
 #include <asm/mach-types.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #include <mach/ocmem.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_memtypes.h>
+#include <mach/ramdump.h>
 #include "q6core.h"
 #include "audio_ocmem.h"
 
+
 #define AUDIO_OCMEM_BUF_SIZE (512 * SZ_1K)
 
+/**
+ * Exercise OCMEM Dump if audio OCMEM state is
+ * one of the following. All other states indicate
+ * audio data is not mapped from DDR to OCMEM and
+ * therefore no need of dump.
+ */
+#define _DO_OCMEM_DUMP_BIT_MASK_\
+		((1 << OCMEM_STATE_MAP_COMPL) |\
+		(1 << OCMEM_STATE_MAP_TRANSITION) |\
+		(1 << OCMEM_STATE_UNMAP_TRANSITION) |\
+		(1 << OCMEM_STATE_SHRINK) |\
+		(1 << OCMEM_STATE_GROW))
+
+/**
+ * Wait for OCMEM driver to process and respond for
+ * ongoing map/unmap request before calling OCMEM dump.
+ */
+#define _WAIT_BFR_DUMP_BIT_MASK_\
+		((1 << OCMEM_STATE_MAP_COMPL) |\
+		(1 << OCMEM_STATE_UNMAP_COMPL) |\
+		(1 << OCMEM_STATE_MAP_FAIL) |\
+		(1 << OCMEM_STATE_UNMAP_FAIL))
+
+#define _MAP_RESPONSE_BIT_MASK_\
+		((1 << OCMEM_STATE_MAP_COMPL) |\
+		(1 << OCMEM_STATE_MAP_FAIL))
+
+
+#define _UNMAP_RESPONSE_BIT_MASK_\
+		((1 << OCMEM_STATE_UNMAP_COMPL) |\
+		(1 << OCMEM_STATE_UNMAP_FAIL))
+
 #define _BIT_MASK_\
-		((1 << OCMEM_STATE_EXIT) |\
+		((1 << OCMEM_STATE_SSR) |\
+		(1 << OCMEM_STATE_EXIT) |\
 		(1 << OCMEM_STATE_GROW) |\
 		(1 << OCMEM_STATE_SHRINK))
 
@@ -89,6 +129,10 @@
 	struct workqueue_struct *audio_ocmem_workqueue;
 	struct workqueue_struct *voice_ocmem_workqueue;
 	bool ocmem_en;
+	bool audio_ocmem_running;
+	void *ocmem_ramdump_dev;
+	struct ramdump_segment ocmem_ramdump_segment;
+	unsigned long ocmem_dump_addr;
 };
 
 static struct audio_ocmem_prv audio_ocmem_lcl;
@@ -114,7 +158,9 @@
 		break;
 	case OCMEM_MAP_FAIL:
 		pr_debug("%s: map fail\n", __func__);
-		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
+		clear_bit_pos(audio_ocmem_lcl.audio_state,
+				OCMEM_STATE_MAP_TRANSITION);
+		set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
 		break;
 	case OCMEM_UNMAP_DONE:
 		pr_debug("%s: unmap done\n", __func__);
@@ -125,8 +171,10 @@
 		break;
 	case OCMEM_UNMAP_FAIL:
 		pr_debug("%s: unmap fail\n", __func__);
-		atomic_set(&audio_ocmem_lcl.audio_state,
-				OCMEM_STATE_UNMAP_FAIL);
+		clear_bit_pos(audio_ocmem_lcl.audio_state,
+				OCMEM_STATE_UNMAP_TRANSITION);
+		set_bit_pos(audio_ocmem_lcl.audio_state,
+			    OCMEM_STATE_UNMAP_FAIL);
 		break;
 	case OCMEM_ALLOC_GROW:
 		rbuf = data;
@@ -170,6 +218,9 @@
 	} else if (test_bit_pos((*state), OCMEM_STATE_EXIT)) {
 		pr_debug("%s: returning exit state\n", __func__);
 		return OCMEM_STATE_EXIT;
+	} else if (test_bit_pos((*state), OCMEM_STATE_SSR)) {
+		pr_debug("%s: returning ssr state\n", __func__);
+		return OCMEM_STATE_SSR;
 	} else
 		return -EINVAL;
 
@@ -278,8 +329,8 @@
 	}
 
 	wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-			test_bit_pos(audio_ocmem_lcl.audio_state,
-				OCMEM_STATE_MAP_COMPL) != 0);
+			(atomic_read(&audio_ocmem_lcl.audio_state) &
+					_MAP_RESPONSE_BIT_MASK_) != 0);
 	atomic_set(&audio_ocmem_lcl.audio_cond, 1);
 
 	mutex_unlock(&audio_ocmem_lcl.protect_lock);
@@ -322,8 +373,9 @@
 			}
 
 			wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-				test_bit_pos(audio_ocmem_lcl.audio_state,
-					OCMEM_STATE_UNMAP_COMPL) != 0);
+				(atomic_read(&audio_ocmem_lcl.audio_state) &
+					     _UNMAP_RESPONSE_BIT_MASK_)
+					     != 0);
 			ret = ocmem_shrink(cid, audio_ocmem_lcl.buf, 0);
 			if (ret) {
 				pr_err("%s: ocmem_shrink failed, state[%d]\n",
@@ -353,8 +405,8 @@
 				goto fail_cmd;
 			}
 			wait_event_interruptible(audio_ocmem_lcl.audio_wait,
-				test_bit_pos(audio_ocmem_lcl.audio_state,
-					OCMEM_STATE_MAP_COMPL) != 0);
+				(atomic_read(&audio_ocmem_lcl.audio_state) &
+						_MAP_RESPONSE_BIT_MASK_) != 0);
 
 			clear_bit_pos(audio_ocmem_lcl.audio_state,
 					OCMEM_STATE_GROW);
@@ -377,8 +429,8 @@
 				}
 				wait_event_interruptible(
 				audio_ocmem_lcl.audio_wait,
-				test_bit_pos(audio_ocmem_lcl.audio_state,
-					OCMEM_STATE_UNMAP_COMPL) != 0);
+				(atomic_read(&audio_ocmem_lcl.audio_state) &
+				_UNMAP_RESPONSE_BIT_MASK_) != 0);
 			}
 
 			if (test_bit_pos(audio_ocmem_lcl.audio_state,
@@ -434,14 +486,15 @@
 				goto fail_cmd;
 			}
 			pr_debug("%s: ocmem_free success\n", __func__);
+		/* Fall through */
+		case OCMEM_STATE_SSR:
 			msm_bus_scale_client_update_request(
 				audio_ocmem_lcl.audio_ocmem_bus_client,
 				0);
 			set_bit_pos(audio_ocmem_lcl.audio_state,
-						OCMEM_STATE_DISABLE);
+					OCMEM_STATE_DISABLE);
 			break;
 
-
 		case -EINVAL:
 			pr_info("%s: audio_cond[%d] audio_state[0x%x]\n",
 				__func__,
@@ -453,6 +506,7 @@
 	ret = 0;
 fail_cmd:
 	pr_debug("%s: exit\n", __func__);
+	audio_ocmem_lcl.audio_ocmem_running = false;
 	return ret;
 }
 
@@ -470,8 +524,11 @@
 	pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n", __func__,
 			 atomic_read(&audio_ocmem_lcl.audio_cond),
 			 atomic_read(&audio_ocmem_lcl.audio_state));
-	set_bit_pos(audio_ocmem_lcl.audio_state,
-				OCMEM_STATE_EXIT);
+	if (!test_bit_pos(audio_ocmem_lcl.audio_state,
+			  OCMEM_STATE_SSR))
+		set_bit_pos(audio_ocmem_lcl.audio_state,
+			    OCMEM_STATE_EXIT);
+
 	wake_up(&audio_ocmem_lcl.audio_wait);
 
 	mutex_unlock(&audio_ocmem_lcl.protect_lock);
@@ -652,6 +709,7 @@
 		}
 		workdata->id = id;
 		workdata->en = enable;
+		audio_ocmem_lcl.audio_ocmem_running = true;
 
 		INIT_WORK(&workdata->work, audio_ocmem_process_workdata);
 		queue_work(audio_ocmem_lcl.audio_ocmem_workqueue,
@@ -684,12 +742,130 @@
 
 	return 0;
 }
+
+static void do_ocmem_ramdump(void)
+{
+	int ret = 0;
+	void *virt = NULL;
+
+	virt = ioremap(audio_ocmem_lcl.ocmem_dump_addr, AUDIO_OCMEM_BUF_SIZE);
+	ret = ocmem_dump(OCMEM_LP_AUDIO,
+			 audio_ocmem_lcl.buf,
+			 (unsigned long)virt);
+	iounmap(virt);
+
+	if (ret)
+		pr_err("%s: ocmem_dump failed\n", __func__);
+
+	audio_ocmem_lcl.ocmem_ramdump_segment.address
+			= (unsigned long)audio_ocmem_lcl.ocmem_dump_addr;
+	audio_ocmem_lcl.ocmem_ramdump_segment.size
+						= AUDIO_OCMEM_BUF_SIZE;
+	ret = do_ramdump(audio_ocmem_lcl.ocmem_ramdump_dev,
+			 &audio_ocmem_lcl.ocmem_ramdump_segment,
+			 1);
+	if (ret < 0)
+		pr_err("%s: do_ramdump failed\n", __func__);
+}
+
+static void process_ocmem_dump(void)
+{
+	int ret = 0;
+
+	set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_SSR);
+
+	if (atomic_read(&audio_ocmem_lcl.audio_state) &
+	    _DO_OCMEM_DUMP_BIT_MASK_) {
+
+		wait_event_interruptible(audio_ocmem_lcl.audio_wait,
+				(atomic_read(&audio_ocmem_lcl.audio_state) &
+				 _WAIT_BFR_DUMP_BIT_MASK_) != 0);
+
+		if (test_bit_pos(audio_ocmem_lcl.audio_state,
+				 OCMEM_STATE_MAP_COMPL) ||
+		    test_bit_pos(audio_ocmem_lcl.audio_state,
+				 OCMEM_STATE_UNMAP_FAIL)) {
+
+			if (audio_ocmem_lcl.ocmem_dump_addr &&
+			    audio_ocmem_lcl.ocmem_ramdump_dev)
+				do_ocmem_ramdump();
+			else
+				pr_err("%s: Error calling ocmem ramdump\n",
+					__func__);
+
+			ret = ocmem_drop(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf,
+					 &audio_ocmem_lcl.mlist);
+			if (ret)
+				pr_err("%s: ocmem_drop failed\n", __func__);
+		}
+	}
+
+	ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+	if (ret)
+		pr_err("%s: ocmem_free failed\n", __func__);
+}
+
+static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
+			     void *_cmd)
+{
+	int ret = NOTIFY_DONE;
+
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+	pr_debug("AO-Notify: Shutdown started\n");
+		break;
+	case SUBSYS_AFTER_SHUTDOWN:
+	pr_debug("AO-Notify: Shutdown Completed\n");
+		break;
+	case SUBSYS_RAMDUMP_NOTIFICATION:
+		pr_debug("AO-Notify: OCMEM dump\n");
+		if (audio_ocmem_lcl.ocmem_en &&
+		    audio_ocmem_lcl.audio_ocmem_running)
+			process_ocmem_dump();
+		pr_debug("AO-Notify: OCMEM dump done\n");
+		break;
+	case SUBSYS_BEFORE_POWERUP:
+		pr_debug("AO-Notify: Powerup started\n");
+		break;
+	case SUBSYS_AFTER_POWERUP:
+		pr_debug("AO-Notify: Powerup completed\n");
+		break;
+	default:
+		pr_err("AO-Notify: Generel: %lu\n", code);
+		break;
+	}
+	return ret;
+}
+
+static struct notifier_block anb = {
+	.notifier_call = lpass_notifier_cb,
+};
+
 static int ocmem_audio_client_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct msm_bus_scale_pdata *audio_ocmem_bus_scale_pdata = NULL;
 
 	pr_debug("%s\n", __func__);
+
+	subsys_notif_register_notifier("adsp", &anb);
+
+	audio_ocmem_lcl.ocmem_dump_addr =
+		allocate_contiguous_memory_nomap(AUDIO_OCMEM_BUF_SIZE,
+						 MEMTYPE_EBI1,
+						 AUDIO_OCMEM_BUF_SIZE);
+
+	if (audio_ocmem_lcl.ocmem_dump_addr) {
+		audio_ocmem_lcl.ocmem_ramdump_dev =
+			create_ramdump_device("audio-ocmem", &pdev->dev);
+
+		if (!audio_ocmem_lcl.ocmem_ramdump_dev)
+			pr_err("%s: audio-ocmem ramdump device failed\n",
+				__func__);
+	} else {
+		pr_err("%s: ocmem dump memory alloc failed\n", __func__);
+	}
+
 	audio_ocmem_lcl.audio_ocmem_workqueue =
 		alloc_workqueue("ocmem_audio_client_driver_audio",
 					WQ_NON_REENTRANT | WQ_UNBOUND, 0);
@@ -715,6 +891,7 @@
 	spin_lock_init(&audio_ocmem_lcl.audio_lock);
 	mutex_init(&audio_ocmem_lcl.protect_lock);
 	audio_ocmem_lcl.ocmem_en = true;
+	audio_ocmem_lcl.audio_ocmem_running = false;
 
 	/* populate platform data */
 	ret = audio_ocmem_platform_data_populate(pdev);
@@ -753,6 +930,7 @@
 	msm_bus_cl_clear_pdata(audio_ocmem_bus_scale_pdata);
 	ocmem_notifier_unregister(audio_ocmem_lcl.audio_hdl,
 					&audio_ocmem_client_nb);
+	free_contiguous_memory_by_paddr(audio_ocmem_lcl.ocmem_dump_addr);
 	return 0;
 }
 static const struct of_device_id msm_ocmem_audio_dt_match[] = {
@@ -771,11 +949,9 @@
 	.remove = ocmem_audio_client_remove,
 };
 
-
 static int __init ocmem_audio_client_init(void)
 {
 	int rc;
-
 	rc = platform_driver_register(&audio_ocmem_driver);
 
 	if (rc)
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 9d6896e..e79a0cf 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -56,6 +56,10 @@
 #define TIMEOUT_MS 1000
 #define Q6AFE_MAX_VOLUME 0x3FFF
 
+static int pcm_afe_instance[2];
+static int proxy_afe_instance[2];
+bool afe_close_done[2] = {true, true};
+
 #define SIZEOF_CFG_CMD(y) \
 		(sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
 
@@ -1061,11 +1065,30 @@
 	}
 
 	if ((port_id == RT_PROXY_DAI_001_RX) ||
-		(port_id == RT_PROXY_DAI_002_TX))
-		return 0;
-	if ((port_id == RT_PROXY_DAI_002_RX) ||
-		(port_id == RT_PROXY_DAI_001_TX))
+		(port_id == RT_PROXY_DAI_002_TX)) {
+		pr_debug("%s: before incrementing pcm_afe_instance %d"\
+			" port_id %d\n", __func__,
+			pcm_afe_instance[port_id & 0x1], port_id);
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+		pcm_afe_instance[port_id & 0x1]++;
+		return 0;
+	}
+	if ((port_id == RT_PROXY_DAI_002_RX) ||
+			(port_id == RT_PROXY_DAI_001_TX)) {
+		pr_debug("%s: before incrementing proxy_afe_instance %d"\
+			" port_id %d\n", __func__,
+			proxy_afe_instance[port_id & 0x1], port_id);
+
+		if (!afe_close_done[port_id & 0x1]) {
+			/*close pcm dai corresponding to the proxy dai*/
+			afe_close(port_id - 0x10);
+			pcm_afe_instance[port_id & 0x1]++;
+			pr_debug("%s: reconfigure afe port again\n", __func__);
+		}
+		proxy_afe_instance[port_id & 0x1]++;
+		afe_close_done[port_id & 0x1] = false;
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+	}
 
 	pr_debug("%s: port id: %#x\n", __func__, port_id);
 
@@ -2618,6 +2641,31 @@
 		goto fail_cmd;
 	}
 	pr_debug("%s: port_id=%d\n", __func__, port_id);
+	if ((port_id == RT_PROXY_DAI_001_RX) ||
+			(port_id == RT_PROXY_DAI_002_TX)) {
+		pr_debug("%s: before decrementing pcm_afe_instance %d\n",
+			__func__, pcm_afe_instance[port_id & 0x1]);
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+		pcm_afe_instance[port_id & 0x1]--;
+		if (!(pcm_afe_instance[port_id & 0x1] == 0 &&
+			proxy_afe_instance[port_id & 0x1] == 0))
+			return 0;
+		else
+			afe_close_done[port_id & 0x1] = true;
+	}
+
+	if ((port_id == RT_PROXY_DAI_002_RX) ||
+		(port_id == RT_PROXY_DAI_001_TX)) {
+		pr_debug("%s: before decrementing proxy_afe_instance %d\n",
+			__func__, proxy_afe_instance[port_id & 0x1]);
+		port_id = VIRTUAL_ID_TO_PORTID(port_id);
+		proxy_afe_instance[port_id & 0x1]--;
+		if (!(pcm_afe_instance[port_id & 0x1] == 0 &&
+			proxy_afe_instance[port_id & 0x1] == 0))
+			return 0;
+		else
+			afe_close_done[port_id & 0x1] = true;
+	}
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 	index = q6audio_get_port_index(port_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c2b824f..59d4de2 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -866,7 +866,6 @@
 				data->reset_proc,
 				this_mmap.apr);
 		apr_reset(this_mmap.apr);
-		atomic_set(&this_mmap.ref_cnt, 0);
 		this_mmap.apr = NULL;
 		reset_custom_topology_flags();
 		set_custom_topology = 1;