Merge "ASoC: msm: Support setting channel map Multi channel PCM playback"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 843da69..3684a3f 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -11,7 +11,7 @@
 KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
 KERNEL_IMG=$(KERNEL_OUT)/arch/arm/boot/Image
 
-DTS_NAMES ?= $(shell $(PERL) -e 'while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD)[a-zA-Z0-9]+)=y/; $$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/; $$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD)[a-zA-Z0-9]+)=y/} print $$arch;' $(KERNEL_CONFIG))
+DTS_NAMES ?= $(shell $(PERL) -e 'while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/; $$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/; $$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/} print $$arch;' $(KERNEL_CONFIG))
 KERNEL_USE_OF ?= $(shell $(PERL) -e '$$of = "n"; while (<>) { if (/CONFIG_USE_OF=y/) { $$of = "y"; break; } } print $$of;' kernel/arch/arm/configs/$(KERNEL_DEFCONFIG))
 
 ifeq "$(KERNEL_USE_OF)" "y"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index a39356c..5b4d3cf 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -5,74 +5,135 @@
 
 Required properties:
 
-- qcom,core-max-time-us:	Maximum time limit in micorseconds for switching clock rate.
-				Limited to this value if switching time takes longer than this limit. Typical value is 100000.
-- qcom,algo-slack-time-us:	Time in microseconds after which the QoS guarantee will kick in
-				and the clock rate will increased as necessary. Typical value is about 30000.
-- qcom,algo-disable-pc-threshold:	If core frequency (kHz) is higher than this value, power collapse is disallowed. Set to 0 for GPU.
-- qcom,algo-ss-window-size:	Steady state window size in microseconds.
-- qcom,algo-ss-util-pct:	When determining the steady state level, this percentage value is used to provide headroom
-				from the utilized cpu to the selected level.
-- qcom,algo-ee-max-util-pct:	When determining the level with the lowest energy, any level that exceeds this busy
-				percentage, for the measured work in the last window, is disqualified for performance reasons.
-- qcom,algo-ss-iobusy-conv:	Used to convert correlation time into assumed IO Busy time, which is removed
-				from measured elapsed time when computing cpu utilization.
+- qcom,core-core-type:	indicates whether this core is a CPU(0) or a GPU(1)
 
+- qcom,algo-disable-pc-threshold:	sets highest frequency at which DCVS
+					will allow the CPU to power collapse.
+- qcom,algo-em-win-size-min-us:		sets minimum Energy Minimization(EM)
+					window size.
+- qcom,algo-em-win-size-max-us:		sets maximum EM window size.
+- qcom,algo-em-max-util-pct:		sets maximum CPU utilization that will
+					not be exceeded by any core when
+					MP-decision decides the number of
+					online cores.
+- qcom,algo-group-id:			specifies a group index of a core.
+- qcom,algo-max-freq-chg-time-us:	shows time taken for the most recent
+					frequency change.
+- qcom,algo-slack-mode-dynamic:	 	specifies if dynamic slack mode is
+					enabled or not.
+- qcom,algo-slack-weight-thresh-pct:	sets occurrence percentage of CPU
+					activity that will make slack timer
+					triggered.
+- qcom,algo-slack-time-min-us:		specifies the slack time that slack
+					timer would be set if the current clock
+					frequency is zero.
+- qcom,algo-slack-time-max-us:		sets maximum slack timer value to be
+					used by slack timer.
+- qcom,algo-ss-win-size-min-us:		sets minimum steady state window size.
+- qcom,algo-ss-win-size-max-us:		sets maximum steady state window size.
+- qcom,algo-ss-util-pct:		sets target CPU utilization during
+					steady-state.
+- qcom,algo-ss-iobusy-conv:		specifies how wait time (i/o busy time)
+					is incorporated into the steady-state
+					algorithm.
+
+- qcom,energy-active-coeff-a:	sets active power equation coefficient a.
+- qcom,energy-active-coeff-b:	sets active power equation coefficient b.
+- qcom,energy-active-coeff-c:	sets active power equation coefficient c.
+- qcom,energy-leakage-coeff-a:	sets leakage power equation coefficient a.
+- qcom,energy-leakage-coeff-b:	sets leakage power equation coefficient b.
+- qcom,energy-leakage-coeff-c:	sets leakage power equation coefficient c.
+- qcom,energy-leakage-coeff-d:	sets leakage power equation coefficient d.
+
+- qcom,power-current-temp:	the current temperature in degCelcius.
+- qcom,power-num-freq:		the number of freq this core supports.
 
 A number of frequency levels are represented as sub-nodes:
 
 required properties:
 - reg:			The index of the frequency entry
 - qcom,freq		The frequency of the DVS entry (in kHZ)
-- qcom,idle-energy: 	The idle energy cost of the entry (in micro watts)
-- qcom,active-energy:	The active energy cost of the entry (in micro watts)
+- qcom,is_trans_level	This frequency is transient step for DCVS
+- qcom,active-energy-offset:	The active energy cost of the entry
+- qcom,leakage-energy-offset: 	The leakage energy cost of the entry
 
 Sample:
 
 qcom,kgsl-3d0@fdb00000 {
 	...
-	qcom,dcvs-core-info {
-		#address-cells = <1>;
-		#size-cells = <0>;
+		qcom,dcvs-core-info {
+			#address-cells = <1>;
+			#size-cells = <0>;
 
-		compatible = "qcom,dcvs-core-info";
+			compatible = "qcom,dcvs-core-info";
 
-		qcom,core-max-time-us = <100000>;
-		qcom,algo-slack-time-us = <39000>;
-		qcom,algo-disable-pc-threshold = <86000>;
-		qcom,algo-ss-window-size = <1000000>;
-		qcom,algo-ss-util-pct = <95>;
-		qcom,algo-em-max-util-pct = <97>;
-		qcom,algo-ss-iobusy-conv = <100>;
+			qcom,num_cores = <1>;
+			qcom,sensors = <0>;
 
-		qcom,dcvs-freq@0 {
-			reg = <0>;
-			qcom,freq = <0>;
-			qcom,idle-energy = <0>;
-			qcom,active-energy = <333932>;
+			qcom,core-core-type = <1>;
+
+			qcom,algo-disable-pc-threshold = <0>;
+			qcom,algo-em-win-size-min-us = <100000>;
+			qcom,algo-em-win-size-max-us = <300000>;
+			qcom,algo-em-max-util-pct = <97>;
+			qcom,algo-group-id = <95>;
+			qcom,algo-max-freq-chg-time-us = <100000>;
+			qcom,algo-slack-mode-dynamic = <100000>;
+			qcom,algo-slack-weight-thresh-pct = <0>;
+			qcom,algo-slack-time-min-us = <39000>;
+			qcom,algo-slack-time-max-us = <39000>;
+			qcom,algo-ss-win-size-min-us = <1000000>;
+			qcom,algo-ss-win-size-max-us = <1000000>;
+			qcom,algo-ss-util-pct = <95>;
+			qcom,algo-ss-iobusy-conv = <100>;
+
+			qcom,energy-active-coeff-a = <2492>;
+			qcom,energy-active-coeff-b = <0>;
+			qcom,energy-active-coeff-c = <0>;
+			qcom,energy-leakage-coeff-a = <11>;
+			qcom,energy-leakage-coeff-b = <157150>;
+			qcom,energy-leakage-coeff-c = <0>;
+			qcom,energy-leakage-coeff-d = <0>;
+
+			qcom,power-current-temp = <25>;
+			qcom,power-num-freq = <4>;
+
+			qcom,dcvs-freq@0 {
+				reg = <0>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@1 {
+				reg = <1>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@2 {
+				reg = <2>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@3 {
+				reg = <3>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <844545>;
+				qcom,leakage-energy-offset = <0>;
+			};
 		};
-
-		qcom,dcvs-freq@1 {
-			reg = <1>;
-			qcom,freq = <0>;
-			qcom,idle-energy = <0>;
-			qcom,active-energy = <497532>;
-		};
-
-		qcom,dcvs-freq@2 {
-			reg = <2>;
-			qcom,freq = <0>;
-			qcom,idle-energy = <0>;
-			qcom,active-energy = <707610>;
-		};
-
-		qcom,dcvs-freq@3 {
-			reg = <3>;
-			qcom,freq = <0>;
-			qcom,idle-energy = <0>;
-			qcom,active-energy = <844545>;
-		};
-	};
 	...
 };
 
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
new file mode 100644
index 0000000..e5fd1b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
@@ -0,0 +1,16 @@
+* Qualcomm's Watchdog Debug Image Controller
+
+The Qualcomm's Watchdog debug image controller is used for enabling/disabling of
+watchdog debug image feature.
+
+Required properties:
+- compatible : should be "qcom,msm-wdog-debug"
+- reg : base page aligned physical base address of the controller and length of
+	memory mapped region.
+
+Example:
+
+	qcom,msm-wdog-debug@fc401000 {
+		compatible = "qcom,msm-wdogi-debug";
+		reg = <0xfc401000 0x1000>;
+	};
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index c584073..f860618 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -31,6 +31,7 @@
 			 component
 - coresight-child-ports : list of input port numbers of the children
 - coresight-default-sink : represents the default compile time CoreSight sink
+- qcom,pc-save : program counter save implemented
 
 Examples:
 
@@ -103,4 +104,5 @@
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <0>;
+		qcom,pc-save;
 	};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
index a6c83d0..88fca69 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -27,6 +27,8 @@
  - vcc_i2c-supply		: Power source required to pull up i2c bus
  - atmel,dig-reg-support	: specify to indicate digital regulator is
 					needed
+ - atmel,need-calibration	: specify to indicate whether calibration is
+					needed during wakeup.
 
 Example:
 	i2c@f9966000 {
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index f5a2590..7a90cc0 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -19,6 +19,19 @@
 Optional properties:
 - qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
   access to the IOMMU configuration registers
+- qcom,iommu-bfb-regs : An array of unsigned 32-bit integers corresponding to
+  BFB register addresses that need to be configured for performance tuning
+  purposes. If this property is present, the qcom,iommu-bfb-data must also be
+  present. Register addresses are specified as an offset from the base of the
+  IOMMU hardware block. This property may be omitted if no BFB register
+  configuration needs to be done for a particular IOMMU hardware instance. The
+  registers specified by this property shall fall within the IOMMU
+  implementation-defined register region.
+- qcom,iommu-bfb-data : An array of unsigned 32-bit integers representing the
+  values to be programmed into the corresponding registers given by the
+  qcom,iommu-bfb-regs property. If this property is present, the
+  qcom,iommu-bfb-regs property shall also be present, and the lengths of both
+  properties shall be the same.
 
 Example:
 
@@ -26,6 +39,8 @@
                 compatible = "qcom,msm-smmu-v2";
                 reg = <0xfda64000 0x10000>;
 		vdd-supply = <&gdsc_iommu>;
+		qcom,iommu-bfb-regs = <0x204c 0x2050>;
+		qcom,iommu-bfb-data = <0xffff 0xffce>;
 
                 qcom,iommu-ctx@fda6c000 {
                         reg = <0xfda6c000 0x1000>;
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
index 7aafd219..9692059 100644
--- a/Documentation/devicetree/bindings/pil/pil-mba.txt
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -10,6 +10,8 @@
 		      first corresponds to the Relay Message Buffer (RMB)
 		      register base. The second specifies the address at which
 		      the primary modem image metadata should be stored.
+- reg-names:	      Names for the above base addresses. "rmb_base" and
+	              "metadata_base" are expected.
 - qcom,firmware-name: Base name of the firmware image. Ex. "modem"
 
 Optional properties:
@@ -21,6 +23,7 @@
 		compatible = "qcom,pil-mba";
 		reg = <0xfc820000 0x0020>,
 		      <0x0d1f0000 0x4000>;
+		reg-names = "rmb_base", "metadata_base";
 
 		qcom,firmware-name = "modem";
 		qcom,depends-on    = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 6193b68..e123bdb 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -7,9 +7,9 @@
 
 Required properties:
 - compatible: "pil-pronto"
-- reg: offset and length of the register set for the device. The first pair
-       corresponds to PRONTO_PMU, the second pair corresponds to CLK_CTL_WCNSS
-       the third pair corresponds to WCNSS_HALTREQ.
+- reg: offset and length of the register set for the device.
+- reg-names: names of the bases for the above registers. "pmu_base", "clk_base",
+             and "halt_base" are expected.
 - vdd_pronto_pll-supply: regulator to supply pronto pll.
 - qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
 
@@ -19,6 +19,7 @@
 		reg = <0xfb21b000 0x3000>,
 		      <0xfc401700 0x4>,
 		      <0xfd485300 0xc>;
+		reg-names = "pmu_base", "clk_base", "halt_base";
 		vdd_pronto_pll-supply = <&pm8941_l12>;
 
 		qcom,firmware-name = "wcnss";
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 308f992..d39c98c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,9 +7,10 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-lpass"
-- reg:		      Two pairs of physical base addresses and region sizes
-		      of memory mapped registers. The first region corresponds
-		      to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
+- reg:		      Pairs of physical base addresses and region sizes of
+		      memory mapped registers.
+- reg-names:	      Names of the bases for the above registers. "qdsp6_base"
+		      and "halt_base" are expected.
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 
 Example:
@@ -17,6 +18,7 @@
 	        compatible = "qcom,pil-q6v5-lpass";
 	        reg = <0xfe200000 0x00100>,
 	              <0xfd485100 0x00010>;
+		reg-names = "qdsp6_base", "halt_base";
 
 	        qcom,firmware-name = "lpass";
 	};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 32c9c35..41ffd8a 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -7,12 +7,11 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-mss"
-- reg:		      Five pairs of physical base addresses and region sizes of
-		      memory mapped registers. The first region corresponds to
-		      QDSP6SS_PUB, the second to the bus port halt register
-		      base, the third to the MSS_RELAY_MSG_BUFFER base, the
-		      fourth to the MSS_RESTART register, and the fifth to the
-		      MSS_CLAMP_IO register.
+- reg:		      Pairs of physical base addresses and region sizes of
+		      memory mapped registers.
+- reg-names:	      Names of the bases for the above registers. "qdsp6_base",
+		      "halt_base", "rmb_base", "restart_reg" and "clamp_reg"
+		      are expected.
 - vdd_mss-supply:     Reference to the regulator that supplies the processor.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
 - qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
@@ -27,6 +26,8 @@
 		      <0xfc820000 0x020>,
 		      <0xfc401680 0x004>,
 		      <0xfc980008 0x004>;
+		reg-names = "qdsp6_base", "halt_base", "rmb_base",
+			    "restart_reg", "clamp_reg";
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt
index 93cba32..4b87f17 100644
--- a/Documentation/devicetree/bindings/pil/pil-venus.txt
+++ b/Documentation/devicetree/bindings/pil/pil-venus.txt
@@ -7,8 +7,9 @@
 
 Required properties:
 - compatible: "pil-venus"
-- reg: offset and length of the register set for the device. The first pair
-       corresponds to VENUS_WRAPPER, the second pair corresponds to VENUS_VBIF.
+- reg: offset and length of the register set for the device.
+- reg-names: names of the bases for the above registers. "wrapper_base" and
+             "vbif_base" are expected.
 - vdd-supply: regulator to supply venus.
 - qcom,firmware-name: Base name of the firmware image. Ex. "venus"
 - qcom,firmware-min-paddr: The lowest addr boundary for firmware image in DDR
@@ -19,6 +20,7 @@
                 compatible = "qcom,pil-venus";
                 reg = <0xfdce0000 0x4000>,
                       <0xfdc80208 0x8>;
+		reg-names = "wrapper_base", "vbif_base";
                 vdd-supply = <&gdsc_venus>;
 
                 qcom,firmware-name = "venus";
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 21d376a..adb93b8 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -11,18 +11,24 @@
 - compatible:	Must be "qcom,qpnp-power-on"
 - reg:		Specifies the SPMI address and size for this PON (power-on) peripheral
 - interrupts:	Specifies the interrupt associated with PON.
+- interrupt-names:	Specify the interrupt names associated with interrupts. Must be
+			one of "kpdpwr", "kpdpwr-bark", "resin", "resin-bark", "cblpwr".
+			Bark interrupts are associated with system reset configuration
+			to allow default reset configuration to be activated. If system
+			reset configuration is not supported then bark interrupts are
+			nops.
 
 Optional properties:
-- qcom,pon-dbc-delay		The debouce delay for the power-key interrupt
-				specifed in us. The value ranges from 2 seconds
+- qcom,pon-dbc-delay		The debounce delay for the power-key interrupt
+				specified in us. The value ranges from 2 seconds
 				to 1/64 of a second. Possible values are -
 				- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
 				- Intermediate value is rounded down to the
 				nearest valid value.
 - qcom,pon_1 ...pon_n		These represent the child nodes which describe
 				the properties (reset, key) for each of the pon
-				reset source. All the child nodes are optional,
-				if none of them are specified the driver fails
+				reset source. All the child nodes are optional.
+				If none of them is specified, the driver fails
 				to register.
 - qcom,system-reset		Specifies that this PON peripheral can be used
 				to reset the system. This property can only be
@@ -32,32 +38,32 @@
 All the below properties are in the sub-node section (properties of the child
 node).
 
+Sub-node required properties:
+- qcom,pon-type			The type of PON/RESET source. The driver
+				currently supports KPDPWR(0), RESIN(1) and
+				CBLPWR(2) pon/reset sources.
+
+Sub-node optional properties:
 - qcom,pull-up			The initial state of the reset pin under
 				consideration.
 				0 = No pull-up
 				1 = pull-up enabled
-				This property is optional and is set to '0'
-				if not specified.
-- qcom,pon-type			The type of PON/RESET source. The driver
-				currently supports KPDPWR(0) and RESIN(1)
-				pon/reset sources. This property must be
-				specified.
+				This property is set to '0' if not specified.
 - qcom,support-reset		Indicates if this PON source supports
 				reset functionality.
 				0 = Not supported
 				1 = Supported
-				This property is optional and is set to '0'
-				if not specified.
-- qcom,s1-timer			The debouce timer for the BARK interrupt for
+				This property is set to '0' if not specified.
+- qcom,s1-timer			The debounce timer for the BARK interrupt for
 				that reset source. Value is specified in ms.
 				Supported values are -
 				- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
 				  1352, 2048, 3072, 4480, 6720, 10256
 				This property must be specified only if
 				'support-reset' is set to 1.
-- qcom,s2-timer			The debouce timer for the S2 reset specified
+- qcom,s2-timer			The debounce timer for the S2 reset specified
 				in ms. On the expiry of this timer, the PMIC
-				executes the reset sequence. Supoprted values -
+				executes the reset sequence. Supported values -
 				- 0, 10, 50, 100, 250, 500, 1000, 2000
 				This property is required only if
 				'support-reset' is set to 1.
@@ -68,7 +74,7 @@
 				'support-reset' is set to 1.
 - linux,code			The input key-code associated with the reset source.
 				The reset source in its default configuration can be
-				used to support standard keys. This property is optional.
+				used to support standard keys.
 
 Example:
 	qcom,power-on@800 {
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 0eb186e..2864fd1 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -48,6 +48,12 @@
 
  - compatible : "qcom,msm-dai-fe"
 
+* msm-pcm-afe
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-afe"
+
 * msm-dai-q6
 
 [First Level Nodes]
@@ -63,6 +69,8 @@
  - compatible : "qcom,msm-dai-q6-dev"
  - qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
                             Value is from 16384 to 16393
+                            BT SCO port ID value from 12288 to 12289
+                            RT Proxy port ID values from 224 to 225 and 240 to 241
 
 * msm-auxpcm
 
@@ -166,6 +174,36 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <16385>;
 		};
+
+		qcom,msm-dai-q6-bt-sco-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12288>;
+		};
+
+		qcom,msm-dai-q6-bt-sco-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12289>;
+		};
+
+		qcom,msm-dai-q6-be-afe-pcm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <224>;
+		};
+
+		qcom,msm-dai-q6-be-afe-pcm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <225>;
+		};
+
+		qcom,msm-dai-q6-afe-proxy-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <241>;
+		};
+
+		qcom,msm-dai-q6-afe-proxy-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <240>;
+		};
 	};
 
         qcom,msm-auxpcm {
diff --git a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
index b5ca08e..63c1e87 100644
--- a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
@@ -10,6 +10,10 @@
 - qcom,pmic-arb-channel : the assigned channel number for channel registers.
 - qcom,pmic-arb-ppid-map : an array used to map a 12-bit PPID to 8-bit APID.
 
+Optional properties:
+- qcom,not-wakeup : boolean property which indicates that SPMI PMIC interrupts
+	should not be treated as wakeup sources
+
 Peripherals on the SPMI bus are identified with a 12-bit identifier (PPID)
 which is composed of a 4-bit slave address and an 8-bit peripheral identifier.
 The PMIC Arbiter hardware uses an 8-bit APID (Arbiter Peripheral Identifier)
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 9c2ce6c..12fbfec 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -6,6 +6,8 @@
 - compatible : should be "qcom,hsusb-otg"
 - regs : offset and length of the register set in the memory map
 - interrupts: IRQ line
+- interrupt-names: OTG interrupt name(s) referenced in interrupts above
+            HSUSB OTG expects "core_irq" and optionally "async_irq".
 - qcom,hsusb-otg-phy-type: PHY type can be one of
             1 - Chipidea 45nm PHY
 	    2 - Synopsis 28nm PHY
@@ -48,6 +50,7 @@
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9690000 0x400>;
 		interrupts = <134>;
+		interrupt-names = "core_irq";
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 08f7312..22ae844 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -8,23 +8,6 @@
 
 	force_ro		Enforce read-only access even if write protect switch is off.
 
-	num_wr_reqs_to_start_packing 	This attribute is used to determine
-	the trigger for activating the write packing, in case the write
-	packing control feature is enabled.
-
-	When the MMC manages to reach a point where num_wr_reqs_to_start_packing
-	write requests could be packed, it enables the write packing feature.
-	This allows us to start the write packing only when it is beneficial
-	and has minimum affect on the read latency.
-
-	The number of potential packed requests that will trigger the packing
-	can be configured via sysfs by writing the required value to:
-	/sys/block/<block_dev_name>/num_wr_reqs_to_start_packing.
-
-	The default value of num_wr_reqs_to_start_packing was determined by
-	running parallel lmdd write and lmdd read operations and calculating
-	the max number of packed writes requests.
-
 SD and MMC Device Attributes
 ============================
 
diff --git a/arch/Kconfig b/arch/Kconfig
index 0d88760..0a3ffe4 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -169,13 +169,6 @@
 	bool
 	depends on PERF_EVENTS
 
-config HAVE_HW_BRKPT_RESERVED_RW_ACCESS
-	bool
-	depends on HAVE_HW_BREAKPOINT
-	help
-	  Some of the hardware might not have r/w access beyond a certain number
-	  of breakpoint register access.
-
 config HAVE_MIXED_BREAKPOINTS_REGS
 	bool
 	depends on HAVE_HW_BREAKPOINT
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d7ebcfe..5d5f9de 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -29,7 +29,7 @@
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
 	select HAVE_REGS_AND_STACK_ACCESS_API
-	#select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
+	select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_GENERIC_HARDIRQS
 	select GENERIC_IRQ_SHOW
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
new file mode 100644
index 0000000..6a88992
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -0,0 +1,33 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ "msm-iommu.dtsi"
+
+&jpeg_iommu {
+	status = "ok";
+};
+
+&mdp_iommu {
+	status = "ok";
+};
+
+&venus_iommu {
+	status = "ok";
+};
+
+&kgsl_iommu {
+	status = "ok";
+};
+
+&vfe_iommu {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index f73abe7..ac984a1 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,37 +12,19 @@
 
 /dts-v1/;
 
-/include/ "skeleton.dtsi"
+/include/ "mpq8092.dtsi"
 
 / {
 	model = "Qualcomm MPQ8092 Simulator";
 	compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
-	interrupt-parent = <&intc>;
-
-	intc: interrupt-controller@f9000000 {
-		compatible = "qcom,msm-qgic2";
-		interrupt-controller;
-		#interrupt-cells = <3>;
-		reg = <0xf9000000 0x1000>,
-		<0xf9002000 0x1000>;
-	};
-
-	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
-		interrupts = <1 2 0>, <1 3 0>;
-		clock-frequency = <19200000>;
-	};
+	qcom,msm-id = <126 16 0>;
 
 	serial@f991f000 {
-		compatible = "qcom,msm-lsuart-v14";
-		reg = <0xf991f000 0x1000>;
-		interrupts = <0 109 0>;
+		status = "ok";
 	};
 
 	serial@f995e000 {
-		compatible = "qcom,msm-lsuart-v14";
-		reg = <0xf995e000 0x1000>;
-		interrupts = <0 114 0>;
+		status = "ok";
 	};
 
 };
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
new file mode 100644
index 0000000..9b51ceb
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -0,0 +1,58 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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"
+/include/ "mpq8092-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
+
+/ {
+	model = "Qualcomm MPQ8092";
+	compatible = "qcom,mpq8092";
+	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>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <1 2 0>, <1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+		status = "disabled";
+	};
+
+	serial@f995e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf995e000 0x1000>;
+		interrupts = <0 114 0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi
new file mode 100644
index 0000000..c48f67d
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi
@@ -0,0 +1,301 @@
+/* Copyright (c) 2012, 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.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s1 {
+			regulator-name = "8019_s1";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-smpa2 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s2 {
+			regulator-name = "8019_s2";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s3 {
+			regulator-name = "8019_s3";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-s4 {
+			regulator-name = "8019_s4";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l1 {
+			regulator-name = "8019_l1";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l2 {
+			regulator-name = "8019_l2";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l3 {
+			regulator-name = "8019_l3";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l4 {
+			regulator-name = "8019_l4";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l5 {
+			regulator-name = "8019_l5";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l6 {
+			regulator-name = "8019_l6";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l7 {
+			regulator-name = "8019_l7";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l8 {
+			regulator-name = "8019_l8";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l9 {
+			regulator-name = "8019_l9";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l10 {
+			regulator-name = "8019_l10";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <11>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l11 {
+			regulator-name = "8019_l11";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l12 {
+			regulator-name = "8019_l12";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <13>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l13 {
+			regulator-name = "8019_l13";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		compatible = "qcom,rpm-regulator-smd-resource";
+		status = "disabled";
+
+		regulator-l14 {
+			regulator-name = "8019_l14";
+			qcom,set = <3>;
+			status = "disabled";
+			compatible = "qcom,rpm-regulator-smd";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
new file mode 100755
index 0000000..e70eb36
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -0,0 +1,355 @@
+/* Copyright (c) 2012, 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.
+ */
+
+&spmi_bus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	interrupt-controller;
+	#interrupt-cells = <3>;
+
+	qcom,pm8019@0 {
+		spmi-slave-container;
+		reg = <0x0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		qcom,power_on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x2>;
+			interrupt-names = "cblpwr";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
+
+			qcom,pon_1 {
+				qcom,pon-type = <2>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+		};
+
+		clkdiv@5b00 {
+			reg = <0x5b00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		clkdiv@5c00 {
+			reg = <0x5c00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		clkdiv@5d00 {
+			reg = <0x5d00 0x100>;
+			compatible = "qcom,qpnp-clkdiv";
+			qcom,cxo-freq = <19200000>;
+		};
+
+		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,pm8019_rtc_rw@6000 {
+				reg = <0x6000 0x100>;
+			};
+
+			qcom,pm8019_rtc_alarm@6100 {
+				reg = <0x6100 0x100>;
+				interrupts = <0x0 0x61 0x1>;
+			};
+		};
+
+		pm8019_gpios: gpios {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8019-gpio";
+
+			gpio@c000 {
+				reg = <0xc000 0x100>;
+				qcom,pin-num = <1>;
+			};
+
+			gpio@c100 {
+				reg = <0xc100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			gpio@c200 {
+				reg = <0xc200 0x100>;
+				qcom,pin-num = <3>;
+			};
+
+			gpio@c300 {
+				reg = <0xc300 0x100>;
+				qcom,pin-num = <4>;
+			};
+
+			gpio@c400 {
+				reg = <0xc400 0x100>;
+				qcom,pin-num = <5>;
+			};
+
+			gpio@c500 {
+				reg = <0xc500 0x100>;
+				qcom,pin-num = <6>;
+			};
+		};
+
+		pm8019_mpps: mpps {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8019-mpp";
+
+			mpp@a000 {
+				reg = <0xa000 0x100>;
+				qcom,pin-num = <1>;
+			};
+
+			mpp@a100 {
+				reg = <0xa100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			mpp@a200 {
+				reg = <0xa200 0x100>;
+				qcom,pin-num = <3>;
+			};
+
+			mpp@a300 {
+				reg = <0xa300 0x100>;
+				qcom,pin-num = <4>;
+			};
+
+			mpp@a400 {
+				reg = <0xa400 0x100>;
+				qcom,pin-num = <5>;
+			};
+
+			mpp@a500 {
+				reg = <0xa500 0x100>;
+				qcom,pin-num = <6>;
+			};
+		};
+	};
+
+	qcom,pm8019@1 {
+		spmi-slave-container;
+		reg = <0x1>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		regulator@1400 {
+			regulator-name = "8019_s1";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1400 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1400 {
+				reg = <0x1400 0x100>;
+			};
+			qcom,ps@1500 {
+				reg = <0x1500 0x100>;
+			};
+			qcom,freq@1600 {
+				reg = <0x1600 0x100>;
+			};
+		};
+
+		regulator@1700 {
+			regulator-name = "8019_s2";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1700 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1700 {
+				reg = <0x1700 0x100>;
+			};
+			qcom,ps@1800 {
+				reg = <0x1800 0x100>;
+			};
+			qcom,freq@1900 {
+				reg = <0x1900 0x100>;
+			};
+		};
+
+		regulator@1a00 {
+			regulator-name = "8019_s3";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1a00 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1a00 {
+				reg = <0x1a00 0x100>;
+			};
+			qcom,ps@1b00 {
+				reg = <0x1b00 0x100>;
+			};
+			qcom,freq@1c00 {
+				reg = <0x1c00 0x100>;
+			};
+		};
+
+		regulator@1d00 {
+			regulator-name = "8019_s4";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x1d00 0x300>;
+			status = "disabled";
+
+			qcom,ctl@1d00 {
+				reg = <0x1d00 0x100>;
+			};
+			qcom,ps@1e00 {
+				reg = <0x1e00 0x100>;
+			};
+			qcom,freq@1f00 {
+				reg = <0x1f00 0x100>;
+			};
+		};
+
+		regulator@4000 {
+			regulator-name = "8019_l1";
+			reg = <0x4000 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4100 {
+			regulator-name = "8019_l2";
+			reg = <0x4100 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4200 {
+			regulator-name = "8019_l3";
+			reg = <0x4200 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4300 {
+			regulator-name = "8019_l4";
+			reg = <0x4300 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4400 {
+			regulator-name = "8019_l5";
+			reg = <0x4400 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4500 {
+			regulator-name = "8019_l6";
+			reg = <0x4500 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4600 {
+			regulator-name = "8019_l7";
+			reg = <0x4600 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4700 {
+			regulator-name = "8019_l8";
+			reg = <0x4700 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4800 {
+			regulator-name = "8019_l9";
+			reg = <0x4800 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4900 {
+			regulator-name = "8019_l10";
+			reg = <0x4900 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4a00 {
+			regulator-name = "8019_l11";
+			reg = <0x4a00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4b00 {
+			regulator-name = "8019_l12";
+			reg = <0x4b00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4c00 {
+			regulator-name = "8019_l13";
+			reg = <0x4c00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4d00 {
+			regulator-name = "8019_l14";
+			reg = <0x4d00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4e00 {
+			regulator-name = "8019_ldo_xo";
+			reg = <0x4e00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@4f00 {
+			regulator-name = "8019_ldo_rfclk";
+			reg = <0x4f00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index 967d5ec..ea83231 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -22,7 +22,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		pm8841_mpps {
+		pm8841_mpps: mpps {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
@@ -34,25 +34,21 @@
 			mpp@a000 {
 				reg = <0xa000 0x100>;
 				qcom,pin-num = <1>;
-				status = "disabled";
 			};
 
 			mpp@a100 {
 				reg = <0xa100 0x100>;
 				qcom,pin-num = <2>;
-				status = "disabled";
 			};
 
 			mpp@a200 {
 				reg = <0xa200 0x100>;
 				qcom,pin-num = <3>;
-				status = "disabled";
 			};
 
 			mpp@a300 {
 				reg = <0xa300 0x100>;
 				qcom,pin-num = <4>;
-				status = "disabled";
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 8560f9f..f1e18cf 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -203,7 +203,7 @@
 			};
 		};
 
-		pm8941_gpios {
+		pm8941_gpios: gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
@@ -215,221 +215,185 @@
 			gpio@c000 {
 				reg = <0xc000 0x100>;
 				qcom,pin-num = <1>;
-				status = "disabled";
 			};
 
 			gpio@c100 {
 				reg = <0xc100 0x100>;
 				qcom,pin-num = <2>;
-				status = "disabled";
 			};
 
 			gpio@c200 {
 				reg = <0xc200 0x100>;
 				qcom,pin-num = <3>;
-				status = "disabled";
 			};
 
 			gpio@c300 {
 				reg = <0xc300 0x100>;
 				qcom,pin-num = <4>;
-				status = "disabled";
 			};
 
 			gpio@c400 {
 				reg = <0xc400 0x100>;
 				qcom,pin-num = <5>;
-				status = "disabled";
 			};
 
 			gpio@c500 {
 				reg = <0xc500 0x100>;
 				qcom,pin-num = <6>;
-				status = "disabled";
 			};
 
 			gpio@c600 {
 				reg = <0xc600 0x100>;
 				qcom,pin-num = <7>;
-				status = "disabled";
 			};
 
 			gpio@c700 {
 				reg = <0xc700 0x100>;
 				qcom,pin-num = <8>;
-				status = "disabled";
 			};
 
 			gpio@c800 {
 				reg = <0xc800 0x100>;
 				qcom,pin-num = <9>;
-				status = "disabled";
 			};
 
 			gpio@c900 {
 				reg = <0xc900 0x100>;
 				qcom,pin-num = <10>;
-				status = "disabled";
 			};
 
 			gpio@ca00 {
 				reg = <0xca00 0x100>;
 				qcom,pin-num = <11>;
-				status = "disabled";
 			};
 
 			gpio@cb00 {
 				reg = <0xcb00 0x100>;
 				qcom,pin-num = <12>;
-				status = "disabled";
 			};
 
 			gpio@cc00 {
 				reg = <0xcc00 0x100>;
 				qcom,pin-num = <13>;
-				status = "disabled";
 			};
 
 			gpio@cd00 {
 				reg = <0xcd00 0x100>;
 				qcom,pin-num = <14>;
-				status = "disabled";
 			};
 
 			gpio@ce00 {
 				reg = <0xce00 0x100>;
 				qcom,pin-num = <15>;
-				status = "disabled";
 			};
 
 			gpio@cf00 {
 				reg = <0xcf00 0x100>;
 				qcom,pin-num = <16>;
-				status = "disabled";
 			};
 
 			gpio@d000 {
 				reg = <0xd000 0x100>;
 				qcom,pin-num = <17>;
-				status = "disabled";
 			};
 
 			gpio@d100 {
 				reg = <0xd100 0x100>;
 				qcom,pin-num = <18>;
-				status = "disabled";
 			};
 
 			gpio@d200 {
 				reg = <0xd200 0x100>;
 				qcom,pin-num = <19>;
-				status = "disabled";
 			};
 
 			gpio@d300 {
 				reg = <0xd300 0x100>;
 				qcom,pin-num = <20>;
-				status = "disabled";
 			};
 
 			gpio@d400 {
 				reg = <0xd400 0x100>;
 				qcom,pin-num = <21>;
-				status = "disabled";
 			};
 
 			gpio@d500 {
 				reg = <0xd500 0x100>;
 				qcom,pin-num = <22>;
-				status = "disabled";
 			};
 
 			gpio@d600 {
 				reg = <0xd600 0x100>;
 				qcom,pin-num = <23>;
-				status = "disabled";
 			};
 
 			gpio@d700 {
 				reg = <0xd700 0x100>;
 				qcom,pin-num = <24>;
-				status = "disabled";
 			};
 
 			gpio@d800 {
 				reg = <0xd800 0x100>;
 				qcom,pin-num = <25>;
-				status = "disabled";
 			};
 
 			gpio@d900 {
 				reg = <0xd900 0x100>;
 				qcom,pin-num = <26>;
-				status = "disabled";
 			};
 
 			gpio@da00 {
 				reg = <0xda00 0x100>;
 				qcom,pin-num = <27>;
-				status = "disabled";
 			};
 
 			gpio@db00 {
 				reg = <0xdb00 0x100>;
 				qcom,pin-num = <28>;
-				status = "disabled";
 			};
 
 			gpio@dc00 {
 				reg = <0xdc00 0x100>;
 				qcom,pin-num = <29>;
-				status = "disabled";
 			};
 
 			gpio@dd00 {
 				reg = <0xdd00 0x100>;
 				qcom,pin-num = <30>;
-				status = "disabled";
 			};
 
 			gpio@de00 {
 				reg = <0xde00 0x100>;
 				qcom,pin-num = <31>;
-				status = "disabled";
 			};
 
 			gpio@df00 {
 				reg = <0xdf00 0x100>;
 				qcom,pin-num = <32>;
-				status = "disabled";
 			};
 
 			gpio@e000 {
 				reg = <0xe000 0x100>;
 				qcom,pin-num = <33>;
-				status = "disabled";
 			};
 
 			gpio@e100 {
 				reg = <0xe100 0x100>;
 				qcom,pin-num = <34>;
-				status = "disabled";
 			};
 
 			gpio@e200 {
 				reg = <0xe200 0x100>;
 				qcom,pin-num = <35>;
-				status = "disabled";
 			};
 
 			gpio@e300 {
 				reg = <0xe300 0x100>;
 				qcom,pin-num = <36>;
-				status = "disabled";
 			};
 		};
 
-		pm8941_mpps {
+		pm8941_mpps: mpps {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
@@ -441,49 +405,41 @@
 			mpp@a000 {
 				reg = <0xa000 0x100>;
 				qcom,pin-num = <1>;
-				status = "disabled";
 			};
 
 			mpp@a100 {
 				reg = <0xa100 0x100>;
 				qcom,pin-num = <2>;
-				status = "disabled";
 			};
 
 			mpp@a200 {
 				reg = <0xa200 0x100>;
 				qcom,pin-num = <3>;
-				status = "disabled";
 			};
 
 			mpp@a300 {
 				reg = <0xa300 0x100>;
 				qcom,pin-num = <4>;
-				status = "disabled";
 			};
 
 			mpp@a400 {
 				reg = <0xa400 0x100>;
 				qcom,pin-num = <5>;
-				status = "disabled";
 			};
 
 			mpp@a500 {
 				reg = <0xa500 0x100>;
 				qcom,pin-num = <6>;
-				status = "disabled";
 			};
 
 			mpp@a600 {
 				reg = <0xa600 0x100>;
 				qcom,pin-num = <7>;
-				status = "disabled";
 			};
 
 			mpp@a700 {
 				reg = <0xa700 0x100>;
 				qcom,pin-num = <8>;
-				status = "disabled";
 			};
 		};
 
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index c92188a..fd652a0 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -181,7 +181,6 @@
 			reg = <0x6e 0x0>;
 			qcom,csi-if = <1>;
 			qcom,csid-core = <0>;
-			qcom,is-vpe = <1>;
 			qcom,flash-type = <0>;
 			qcom,mount-angle = <90>;
 			qcom,sensor-name = "s5k3l1yx";
@@ -222,8 +221,7 @@
 			compatible = "qcom,ov2720";
 			reg = <0x6c 0x0>;
 			qcom,csi-if = <1>;
-			qcom,csid-core = <1>;
-			qcom,is-vpe = <1>;
+			qcom,csid-core = <0>;
 			qcom,flash-type = <0>;
 			qcom,mount-angle = <0>;
 			qcom,sensor-name = "ov2720";
@@ -257,5 +255,40 @@
 			qcom,camera-type = <1>;
 			qcom,sensor-type = <0>;
 		};
+
+		qcom,camera@90 {
+			compatible = "qcom,mt9m114";
+			reg = <0x90 0x0>;
+			qcom,csi-if = <1>;
+			qcom,csid-core = <0>;
+			qcom,flash-type = <0>;
+			qcom,mount-angle = <0>;
+			qcom,sensor-name = "mt9m114";
+			cam_vdig-supply = <&pm8941_l3>;
+			cam_vana-supply = <&pm8941_l17>;
+			cam_vio-supply = <&pm8941_lvs3>;
+			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+			qcom,cam-vreg-type = <0 0 1>;
+			qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+			qcom,cam-vreg-op-mode = <105000 80000 0>;
+			qcom,gpio-no-mux = <0>;
+			gpios = <&msmgpio 16 0>,
+				<&msmgpio 92 0>;
+			qcom,gpio-common-tbl-num = <0>;
+			qcom,gpio-common-tbl-flags = <1>;
+			qcom,gpio-common-tbl-label = "CAMIF_MCLK";
+			qcom,gpio-req-tbl-num = <1>;
+			qcom,gpio-req-tbl-flags = <0>;
+			qcom,gpio-req-tbl-label = "CAM_RESET1";
+			qcom,gpio-set-tbl-num = <1 1>;
+			qcom,gpio-set-tbl-flags = <0 2>;
+			qcom,gpio-set-tbl-delay = <1000 4000>;
+			qcom,csi-lane-assign = <0x4320>;
+			qcom,csi-lane-mask = <0x3>;
+			qcom,csi-phy-sel = <1>;
+			qcom,camera-type = <1>;
+			qcom,sensor-type = <1>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 7aeb33c..aff0adc 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -168,3 +168,196 @@
 	cd-gpios = <&msmgpio 62 0x1>;
 	wp-gpios = <&pm8941_gpios 29 0x1>;
 };
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-select = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		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,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 0b09bc8..ee3df10 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -141,6 +141,7 @@
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <0>;
+		qcom,pc-save;
 	};
 
 	etm1: etm@fc33d000 {
@@ -153,6 +154,7 @@
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <1>;
+		qcom,pc-save;
 	};
 
 	etm2: etm@fc33e000 {
@@ -165,6 +167,7 @@
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <2>;
+		qcom,pc-save;
 	};
 
 	etm3: etm@fc33f000 {
@@ -177,6 +180,7 @@
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <3>;
+		qcom,pc-save;
 	};
 
 	csr: csr@fc302000 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-fluid.dts
new file mode 100644
index 0000000..b1d467e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-fluid.dts
@@ -0,0 +1,366 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8974 FLUID";
+	compatible = "qcom,msm8974-fluid", "qcom,msm8974";
+	qcom,msm-id = <126 3 0>;
+
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0  0 760 1424>;
+			atmel,display-coords = <0 0 720 1280>;
+			atmel,i2c-pull-up = <1>;
+			atmel,cfg_1 {
+				atmel,family-id = <0x82>;
+				atmel,variant-id = <0x19>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			};
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@2 {
+			compatible = "micrel,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <94 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&pm8941_mpps 6 0>;
+			vdd-io-supply = <&spi_eth_vreg>;
+			vdd-phy-supply = <&spi_eth_vreg>;
+		};
+	};
+};
+
+&sdcc1 {
+	qcom,sdcc-bus-width = <4>;
+};
+
+&sdcc2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+};
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-select = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		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,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
deleted file mode 100644
index dac87a3..0000000
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ /dev/null
@@ -1,273 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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.
- */
-
-&spmi_bus {
-
-	qcom,pm8941@0 {
-
-		pm8941_gpios: pm8941_gpios {
-
-			gpio@c000 {
-				status = "ok";
-			};
-
-			gpio@c100 {
-				status = "ok";
-			};
-
-			gpio@c200 {
-				qcom,mode = <0>;
-				qcom,pull = <0>;
-				qcom,vin-sel = <2>;
-				qcom,select = <0>;
-				status = "ok";
-			};
-
-			gpio@c300 {
-				qcom,mode = <0>;
-				qcom,pull = <0>;
-				qcom,vin-sel = <2>;
-				qcom,select = <0>;
-				status = "ok";
-			};
-
-			gpio@c400 {
-				qcom,mode = <0>;
-				qcom,pull = <0>;
-				qcom,vin-sel = <2>;
-				qcom,select = <0>;
-				status = "ok";
-			};
-
-			gpio@c500 {
-				status = "ok";
-			};
-
-			gpio@c600 {
-				status = "ok";
-			};
-
-			gpio@c700 {
-				status = "ok";
-			};
-
-			gpio@c800 {
-				status = "ok";
-			};
-
-			gpio@c900 {
-				status = "ok";
-			};
-
-			gpio@ca00 {
-				status = "ok";
-			};
-
-			gpio@cb00 {
-				status = "ok";
-			};
-
-			gpio@cc00 {
-				status = "ok";
-			};
-
-			gpio@cd00 {
-				status = "ok";
-			};
-
-			gpio@ce00 {
-				status = "ok";
-				qcom,mode = <1>;
-				qcom,output-type = <0>;
-				qcom,pull = <5>;
-				qcom,vin-sel = <2>;
-				qcom,out-strength = <3>;
-				qcom,src-select = <2>;
-				qcom,master-en = <1>;
-			};
-
-			gpio@cf00 {
-				status = "ok";
-			};
-
-			gpio@d000 {
-				status = "ok";
-			};
-
-			gpio@d100 {
-				status = "ok";
-			};
-
-			gpio@d200 {
-				status = "ok";
-				qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
-				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,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
-				qcom,master-en = <1>;
-			};
-
-			gpio@d300 {
-				status = "ok";
-			};
-
-			gpio@d400 {
-				status = "ok";
-			};
-
-			gpio@d500 {
-				status = "ok";
-			};
-
-			gpio@d600 {
-				status = "ok";
-			};
-
-			gpio@d700 {
-				status = "ok";
-			};
-
-			gpio@d800 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@d900 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@da00 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@db00 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@dc00 {
-				qcom,pull = <0>; /* set to default pull */
-				qcom,master-en = <1>;
-				qcom,vin-sel = <2>; /* select 1.8 V source */
-				status = "ok";
-			};
-
-			gpio@dd00 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@de00 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@df00 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@e000 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@e100 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@e200 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-
-			gpio@e300 {
-				qcom,out-strength = <1>;
-				status = "ok";
-			};
-		};
-
-		pm8941_mpps: pm8941_mpps {
-
-			mpp@a000 {
-				status = "ok";
-			};
-
-			mpp@a100 {
-				status = "ok";
-			};
-
-			mpp@a200 {
-				status = "ok";
-			};
-
-			mpp@a300 {
-				status = "ok";
-			};
-
-			mpp@a400 {
-				status = "ok";
-				/* SPI_ETH config */
-				qcom,mode = <1>; /* DIG_OUT */
-				qcom,output-type = <0>; /* CMOS */
-				qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-				qcom,src-select = <0>; /* CONSTANT */
-				qcom,master-en = <1>; /* ENABLE MPP */
-			};
-
-			mpp@a500 {
-				status = "ok";
-				/* SPI_ETH_RST config */
-				qcom,mode = <1>; /* DIG_OUT */
-				qcom,output-type = <0>; /* CMOS */
-				qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-				qcom,src-select = <0>; /* CONSTANT */
-				qcom,master-en = <1>; /* ENABLE MPP */
-			};
-
-			mpp@a600 {
-				status = "ok";
-			};
-
-			mpp@a700 {
-				status = "ok";
-			};
-		};
-	};
-
-	qcom,pm8841@4 {
-
-		pm8841_mpps: pm8841_mpps {
-
-			mpp@a000 {
-				status = "ok";
-			};
-
-			mpp@a100 {
-				status = "ok";
-			};
-
-			mpp@a200 {
-				status = "ok";
-			};
-
-			mpp@a300 {
-				status = "ok";
-			};
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 2312b02..017aea9 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -85,40 +85,68 @@
 
 			compatible = "qcom,dcvs-core-info";
 
-			qcom,core-max-time-us = <100000>;
-			qcom,algo-slack-time-us = <39000>;
-			qcom,algo-disable-pc-threshold = <86000>;
-			qcom,algo-ss-window-size = <1000000>;
-			qcom,algo-ss-util-pct = <95>;
+			qcom,core-core-type = <1>;
+
+			qcom,algo-disable-pc-threshold = <0>;
+			qcom,algo-em-win-size-min-us = <100000>;
+			qcom,algo-em-win-size-max-us = <300000>;
 			qcom,algo-em-max-util-pct = <97>;
+			qcom,algo-group-id = <95>;
+			qcom,algo-max-freq-chg-time-us = <100000>;
+			qcom,algo-slack-mode-dynamic = <100000>;
+			qcom,algo-slack-weight-thresh-pct = <0>;
+			qcom,algo-slack-time-min-us = <39000>;
+			qcom,algo-slack-time-max-us = <39000>;
+			qcom,algo-ss-win-size-min-us = <1000000>;
+			qcom,algo-ss-win-size-max-us = <1000000>;
+			qcom,algo-ss-util-pct = <95>;
 			qcom,algo-ss-iobusy-conv = <100>;
 
+			qcom,energy-active-coeff-a = <2492>;
+			qcom,energy-active-coeff-b = <0>;
+			qcom,energy-active-coeff-c = <0>;
+			qcom,energy-leakage-coeff-a = <11>;
+			qcom,energy-leakage-coeff-b = <157150>;
+			qcom,energy-leakage-coeff-c = <0>;
+			qcom,energy-leakage-coeff-d = <0>;
+
+			qcom,power-current-temp = <25>;
+			qcom,power-num-freq = <4>;
+
 			qcom,dcvs-freq@0 {
 				reg = <0>;
 				qcom,freq = <0>;
-				qcom,idle-energy = <0>;
-				qcom,active-energy = <333932>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
 			};
 
 			qcom,dcvs-freq@1 {
 				reg = <1>;
 				qcom,freq = <0>;
-				qcom,idle-energy = <0>;
-				qcom,active-energy = <497532>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
 			};
 
 			qcom,dcvs-freq@2 {
 				reg = <2>;
 				qcom,freq = <0>;
-				qcom,idle-energy = <0>;
-				qcom,active-energy = <707610>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
 			};
 
 			qcom,dcvs-freq@3 {
 				reg = <3>;
 				qcom,freq = <0>;
-				qcom,idle-energy = <0>;
-				qcom,active-energy = <844545>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <844545>;
+				qcom,leakage-energy-offset = <0>;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 1893ae4..9b5aaac 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -70,7 +70,7 @@
 			reg = <28>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2B4000>;
+			qcom,memory-reservation-size = <0x314000>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index 5de2d43..2abc1d5 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -24,4 +24,195 @@
 	};
 };
 
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
 
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-select = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		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,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 344aa7f..ca98706 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -18,6 +18,8 @@
 		reg-names = "mdp_phys", "vbif_phys";
 		interrupts = <0 72 0>;
 		vdd-supply = <&gdsc_mdss>;
+		qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+		qcom,memory-reservation-size = <0x800000>; /* size 8MB */
 	};
 
 	mdss_dsi: qcom,mdss_dsi@fd922800 {
@@ -55,7 +57,7 @@
 
 	qcom,mdss_wb_panel {
 		compatible = "qcom,mdss_wb";
-		qcom,mdss_pan_res = <640 480>;
+		qcom,mdss_pan_res = <1920 1080>;
 		qcom,mdss_pan_bpp = <24>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index ed89368..00aec9f 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,7 @@
 / {
 	model = "Qualcomm MSM 8974 MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
-	qcom,msm-id = <126 8 0>, <126 3 0>;
+	qcom,msm-id = <126 8 0>;
 
 	serial@f991e000 {
 		status = "ok";
@@ -167,3 +167,196 @@
 	interrupt-names = "core_irq", "bam_irq", "status_irq";
 	cd-gpios = <&msmgpio 62 0x1>;
 };
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,select = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-select = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		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,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-select = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index da0e1e5..b992e86 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -239,6 +239,19 @@
 		qcom,bam-dma-res-pipes = <6>;
 	};
 
+	spi@f9966000 {
+		compatible = "qcom,spi-qup-v2";
+		cell-index = <7>;
+		reg = <0xf9966000 0x1000>;
+		interrupts = <0 104 0>;
+		spi-max-frequency = <19200000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 56 0>, /* CLK  */
+			<&msmgpio 54 0>, /* MISO */
+			<&msmgpio 53 0>; /* MOSI */
+		cs-gpios = <&msmgpio 55 0>;
+	};
 
 	slim@fe12f000 {
 		cell-index = <1>;
@@ -306,7 +319,6 @@
 		qcom,audio-routing =
 			"RX_BIAS", "MCLK",
 			"LDO_H", "MCLK",
-			"HEADPHONE", "LDO_H",
 			"Ext Spk Bottom Pos", "LINEOUT1",
 			"Ext Spk Bottom Neg", "LINEOUT3",
 			"Ext Spk Top Pos", "LINEOUT2",
@@ -633,6 +645,7 @@
 		compatible = "qcom,pil-q6v5-lpass";
 		reg = <0xfe200000 0x00100>,
 		      <0xfd485100 0x00010>;
+		reg-names = "qdsp6_base", "halt_base";
 
 		qcom,firmware-name = "adsp";
 	};
@@ -673,6 +686,10 @@
 		compatible = "qcom,msm-dai-fe";
 	};
 
+	qcom,msm-pcm-afe {
+		compatible = "qcom,msm-pcm-afe";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -684,6 +701,36 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <16385>;
 		};
+
+		qcom,msm-dai-q6-bt-sco-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12288>;
+		};
+
+		qcom,msm-dai-q6-bt-sco-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12289>;
+		};
+
+		qcom,msm-dai-q6-be-afe-pcm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <224>;
+		};
+
+		qcom,msm-dai-q6-be-afe-pcm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <225>;
+		};
+
+		qcom,msm-dai-q6-afe-proxy-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <241>;
+		};
+
+		qcom,msm-dai-q6-afe-proxy-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <240>;
+		};
 	};
 
 	qcom,msm-auxpcm {
@@ -727,6 +774,9 @@
 		      <0xfc820000 0x020>,
 		      <0xfc401680 0x004>,
 		      <0xfc980008 0x004>;
+		reg-names = "qdsp6_base", "halt_base", "rmb_base",
+			    "restart_reg", "clamp_reg";
+
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
@@ -737,6 +787,7 @@
 		compatible = "qcom,pil-mba";
 		reg = <0xfc820000 0x0020>,
 		      <0x0d1fc000 0x4000>;
+		reg-names = "rmb_base", "metadata_base";
 
 		qcom,firmware-name = "modem";
 		qcom,depends-on    = "mba";
@@ -747,6 +798,7 @@
 		reg = <0xfb21b000 0x3000>,
 		      <0xfc401700 0x4>,
 		      <0xfd485300 0xc>;
+		reg-names = "pmu_base", "clk_base", "halt_base";
 		vdd_pronto_pll-supply = <&pm8941_l12>;
 
 		qcom,firmware-name = "wcnss";
@@ -851,6 +903,7 @@
 		compatible = "qcom,pil-venus";
 		reg = <0xfdce0000 0x4000>,
 		      <0xfdc80208 0x8>;
+		reg-names = "wrapper_base", "vbif_base";
 		vdd-supply = <&gdsc_venus>;
 
 		qcom,firmware-name = "venus";
@@ -992,11 +1045,16 @@
 		reg = <0xfc834000 0x7000>;
 		interrupts = <0 29 1>;
 	};
+
+        qcom,msm-wdog-debug@fc401000 {
+               compatible = "qcom,msm-wdog-debug";
+               reg = <0xfc401000 0x1000>;
+        };
+
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
 /include/ "msm-pm8841.dtsi"
 /include/ "msm-pm8941.dtsi"
 /include/ "msm8974-regulator.dtsi"
-/include/ "msm8974-gpio.dtsi"
 /include/ "msm8974-clock.dtsi"
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 8e3f4b8..e39a72a 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -117,10 +117,9 @@
 		qcom,vctl-port = <0x0>;
 		qcom,phase-port = <0x1>;
 		qcom,saw2-spm-cmd-ret = [00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 0b 42 07 44 22 50 02 32 50
-				0f];
-		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 0b 42 07 01 b0 12 44 a0
-				50 02 32 a0 50 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+				50 02 32 50 0f];
 	};
 
 	qcom,lpm-resources {
@@ -385,8 +384,8 @@
 			<40  95>;
 	};
 
-	qcom,pc-cntr@fe800000 {
+	qcom,pc-cntr@fe805664 {
 		compatible = "qcom,pc-cntr";
-		reg = <0xfe800664 0x40>;
+		reg = <0xfe805664 0x40>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dts
index 6733f59..aa1ec92 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-cdp.dts
@@ -19,3 +19,44 @@
 	compatible = "qcom,msm9625-cdp", "qcom,msm9625";
 	qcom,msm-id = <134 1 0>;
 };
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+};
+
+&pm8019_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-mtp.dts
index 32185dc..3ec949f 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-mtp.dts
@@ -19,3 +19,44 @@
 	compatible = "qcom,msm9625-mtp", "qcom,msm9625";
 	qcom,msm-id = <134 8 0>;
 };
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+};
+
+&pm8019_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
new file mode 100644
index 0000000..c42af2c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -0,0 +1,164 @@
+/* Copyright (c) 2012, 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.
+ */
+
+&spmi_bus {
+	qcom,pm8019@1 {
+		pm8019_s1: regulator@1400 {
+			regulator-min-microvolt = <800000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			status = "okay";
+		};
+
+		pm8019_s2: regulator@1700 {
+			regulator-min-microvolt = <1250000>;
+			regulator-max-microvolt = <1250000>;
+			qcom,system-load = <100000>;
+			qcom,enable-time = <500>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_s3: regulator@1a00 {
+			regulator-min-microvolt = <1100000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,system-load = <100000>;
+			qcom,enable-time = <500>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_s4: regulator@1d00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2075000>;
+			qcom,system-load = <100000>;
+			qcom,enable-time = <500>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l1: regulator@4000 {
+			parent-supply = <&pm8019_s2>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l2: regulator@4100 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l3: regulator@4200 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l4: regulator@4300 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l5: regulator@4400 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l6: regulator@4500 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l7: regulator@4600 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l8: regulator@4700 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l9: regulator@4800 {
+			parent-supply = <&pm8019_s2>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l10: regulator@4900 {
+			parent-supply = <&pm8019_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l11: regulator@4a00 {
+			parent-supply = <&pm8019_s4>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l12: regulator@4b00 {
+			parent-supply = <&pm8019_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,system-load = <10000>;
+			qcom,enable-time = <200>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8019_l13: regulator@4c00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+
+		pm8019_l14: regulator@4d00 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,enable-time = <200>;
+			status = "okay";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-rumi.dts b/arch/arm/boot/dts/msm9625-rumi.dts
index e4fa000..dadb3f7 100644
--- a/arch/arm/boot/dts/msm9625-rumi.dts
+++ b/arch/arm/boot/dts/msm9625-rumi.dts
@@ -18,4 +18,9 @@
 	model = "Qualcomm MSM 9625 RUMI";
 	compatible = "qcom,msm9625-rumi", "qcom,msm9625";
 	qcom,msm-id = <134 15 0>;
+
+	chosen{
+		bootargs = "root=/dev/ram rw init=/init console=ttyHSL0,115200n8 initrd=0x00000000,0x00000000 mem=29M@0x00200000 mem=10M@0x07600000";
+
+	};
 };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 8ad3b66..f50d14f 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -48,7 +48,7 @@
 		reg = <0xF9021000 0x1000>;
 		interrupts = <0 7 0>;
 		irq-is-not-percpu;
-		clock-frequency = <5000000>;
+		clock-frequency = <19200000>;
 	};
 
 	qcom,sps@f9980000 {
@@ -66,6 +66,26 @@
 		interrupts = <0 109 0>;
 	};
 
+	usb@f9a55000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0xf9a55000 0x400>;
+		interrupts = <0 134 0 0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
+		HSUSB_VDDCX-supply = <&pm8019_l12>;
+		HSUSB_1p8-supply = <&pm8019_l2>;
+		HSUSB_3p3-supply = <&pm8019_l4>;
+
+		qcom,hsusb-otg-phy-type = <2>;
+		qcom,hsusb-otg-mode = <1>;
+		qcom,hsusb-otg-otg-control = <1>;
+		qcom,hsusb-otg-disable-reset;
+	};
+
+	android_usb@fc42b0c8 {
+		compatible = "qcom,android-usb";
+		reg = <0xfc42b0c8 0xc8>;
+	};
+
 	qcom,nand@f9ac0000 {
 		compatible = "qcom,msm-nand";
 		reg = <0xf9ac0000 0x1000>,
@@ -106,4 +126,41 @@
 		qcom,pet-time = <10000>;
 		qcom,ipi-ping = <0>;
 	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+	spmi_bus: qcom,spmi@fc4c0000 {
+		cell-index = <0>;
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>;
+		/* 190,ee0_krait_hlos_spmi_periph_irq */
+		/* 187,channel_0_krait_hlos_trans_done_irq */
+		interrupts = <0 190 0 0 187 0>;
+		qcom,not-wakeup;
+		qcom,pmic-arb-ee = <0>;
+		qcom,pmic-arb-channel = <0>;
+		qcom,pmic-arb-ppid-map = <0x02400000>, /* TEMP_ALARM */
+					 <0x03100001>, /* VADC1_USR */
+					 <0x06100002>, /* RTC_ALARM */
+					 <0x06200003>, /* RTC_TIMER */
+					 <0x0a000004>, /* MPP1 */
+					 <0x0a100005>, /* MPP2 */
+					 <0x0a200006>, /* MPP3 */
+					 <0x0a300007>, /* MPP4 */
+					 <0x0a400008>, /* MPP5 */
+					 <0x0a500009>, /* MPP6 */
+					 <0x0c20000a>, /* GPIO3 */
+					 <0x0c30000b>, /* GPIO4 */
+					 <0x0c50000c>, /* GPIO6 */
+					 <0x0080000d>; /* PON */
+	};
 };
+
+/include/ "msm-pm8019-rpm-regulator.dtsi"
+/include/ "msm-pm8019.dtsi"
+/include/ "msm9625-regulator.dtsi"
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 9dd4347..6b8a374 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1167,41 +1167,35 @@
 /*
  * Configure the GIC after we come out of power collapse.
  * This function will configure some of the GIC registers so as to prepare the
- * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
- * core1 out of GDFS.
+ * secondary cores to receive an SPI(ACSR_MP_CORE_IPC1/IPC2/IPC3, 40/92/93),
+ * which will bring cores out of GDFS.
  */
-void core1_gic_configure_and_raise(void)
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu)
 {
 	struct gic_chip_data *gic = &gic_data[0];
+	struct irq_data *d = irq_get_irq_data(irq);
 	void __iomem *base = gic_data_dist_base(gic);
-	unsigned int value = 0;
+	unsigned int value = 0, byte_offset, offset, bit;
 	unsigned long flags;
 
+	offset = ((gic_irq(d) / 32) * 4);
+	bit = BIT(gic_irq(d) % 32);
+
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
-	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
+	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + offset);
+	__raw_writel(value | bit, base + GIC_DIST_ACTIVE_BIT + offset);
 	mb();
 
-	value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
-	value |= BIT(13);
-	__raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+	value = __raw_readl(base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
+	byte_offset = (gic_irq(d) % 4) * 8;
+	value |= 1 << (cpu + byte_offset);
+	__raw_writel(value, base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
 	mb();
 
-	value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
-	value |= BIT(1);
-	__raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+	value =  __raw_readl(base + GIC_DIST_ENABLE_SET + offset);
+	__raw_writel(value | bit, base + GIC_DIST_ENABLE_SET + offset);
 	mb();
 
-	value =  __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
-	mb();
-
-	value =  __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
-	mb();
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index afe528d..45d52e4 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -347,6 +347,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MSM_WFD=y
 CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -505,3 +506,4 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CONTROL_TRACE=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 4c9383d..465598f 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -351,6 +351,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MSM_WFD=y
 CONFIG_USER_RC_INPUT=y
 CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -513,6 +514,7 @@
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_PID_IN_CONTEXTIDR=y
@@ -522,3 +524,4 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CONTROL_TRACE=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 392e062..2f1833e 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -57,6 +57,7 @@
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_MODEM_SSR_8974=y
 CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_WCNSS_SSR_8974=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_BUS_SCALING=y
@@ -297,6 +298,7 @@
 CONFIG_MSM_CSI2_REGISTER=y
 CONFIG_MSM_ISPIF=y
 CONFIG_S5K3L1YX=y
+CONFIG_MT9M114=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -369,6 +371,7 @@
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
 CONFIG_MSM_QDSS=y
+CONFIG_MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -399,3 +402,4 @@
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index d54e19e..1230fbe 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -49,6 +49,7 @@
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_PIL_LPASS_QDSP6V5=y
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_MSM_PIL_MBA=y
@@ -56,6 +57,7 @@
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_MODEM_SSR_8974=y
 CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_WCNSS_SSR_8974=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_BUS_SCALING=y
@@ -71,8 +73,9 @@
 CONFIG_MSM_L1_ERR_PANIC=y
 CONFIG_MSM_L1_ERR_LOG=y
 CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
-CONFIG_MSM_L2_ERP_1BIT_PANIC=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -272,9 +275,9 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
+CONFIG_QPNP_BMS=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
-CONFIG_QPNP_BMS=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
 CONFIG_WCD9320_CODEC=y
@@ -288,7 +291,7 @@
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MSM_CAMERA_V4L2=y
-CONFIG_MSM_WFD=y
+CONFIG_MT9M114=y
 CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
@@ -300,6 +303,7 @@
 CONFIG_MSM_CSI2_REGISTER=y
 CONFIG_MSM_ISPIF=y
 CONFIG_S5K3L1YX=y
+CONFIG_MSM_WFD=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -372,6 +376,7 @@
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
 CONFIG_MSM_QDSS=y
+CONFIG_MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -393,7 +398,6 @@
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
@@ -405,6 +409,7 @@
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_PID_IN_CONTEXTIDR=y
@@ -416,3 +421,4 @@
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 0057062..284f5fc 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -45,24 +45,22 @@
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
 CONFIG_USE_OF=y
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_SUSPEND is not set
-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_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IPV6=y
 # CONFIG_WIRELESS is not set
+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
@@ -89,18 +87,33 @@
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
 # CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_QPNP=y
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
 CONFIG_SPS=y
+CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_POWER_ON=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index ad12bcd..72c3c27 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -62,7 +62,7 @@
 
 void msm_gic_save(void);
 void msm_gic_restore(void);
-void core1_gic_configure_and_raise(void);
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu);
 #endif
 
 #endif
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index ff2c0ad..1692129 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -216,6 +216,20 @@
 	return core_has_mismatch_brps() ? brps - 1 : brps;
 }
 
+/* Determine if halting mode is enabled */
+static int halting_mode_enabled(void)
+{
+	u32 dscr;
+
+	ARM_DBG_READ(c1, 0, dscr);
+
+	if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
+		      "halting debug mode enabled. "
+		      "Unable to access hardware resources.\n"))
+		return -EPERM;
+	return 0;
+}
+
 /*
  * In order to access the breakpoint/watchpoint control registers,
  * we must be running in debug monitor mode. Unfortunately, we can
@@ -225,16 +239,14 @@
 static int enable_monitor_mode(void)
 {
 	u32 dscr;
-	int ret = 0;
+	int ret;
 
 	ARM_DBG_READ(c1, 0, dscr);
 
 	/* Ensure that halting mode is disabled. */
-	if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
-		"halting debug mode enabled. Unable to access hardware resources.\n")) {
-		ret = -EPERM;
+	ret = halting_mode_enabled();
+	if (ret)
 		goto out;
-	}
 
 	/* If monitor mode is already enabled, just return. */
 	if (dscr & ARM_DSCR_MDBGEN)
@@ -853,18 +865,6 @@
 	return ret;
 }
 
-static void reset_brps_reserved_reg(int n)
-{
-	int i;
-
-	/* we must also reset any reserved registers. */
-	for (i = 0; i < n; ++i) {
-		write_wb_reg(ARM_BASE_BCR + i, 0UL);
-		write_wb_reg(ARM_BASE_BVR + i, 0UL);
-	}
-
-}
-
 /*
  * One-time initialisation.
  */
@@ -947,19 +947,21 @@
 	isb();
 
 reset_regs:
-	if (enable_monitor_mode())
+	if (halting_mode_enabled())
 		return;
 
-#ifdef CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS
-	reset_brps_reserved_reg(core_num_brps);
-#else
-	reset_brps_reserved_reg(core_num_brps + core_num_reserved_brps);
-#endif
+	/* We must also reset any reserved registers. */
+	raw_num_brps = get_num_brp_resources();
+	for (i = 0; i < raw_num_brps; ++i) {
+		write_wb_reg(ARM_BASE_BCR + i, 0UL);
+		write_wb_reg(ARM_BASE_BVR + i, 0UL);
+	}
 
 	for (i = 0; i < core_num_wrps; ++i) {
 		write_wb_reg(ARM_BASE_WCR + i, 0UL);
 		write_wb_reg(ARM_BASE_WVR + i, 0UL);
 	}
+	enable_monitor_mode();
 }
 
 static int __cpuinit dbg_reset_notify(struct notifier_block *self,
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6df6e13..2020422 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -357,6 +357,8 @@
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
 endmenu
 
 choice
@@ -410,7 +412,6 @@
 	select HAVE_ARCH_HAS_CURRENT_TIMER
 	select MSM_JTAG if MSM_QDSS
 	bool
-	select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
 
 config  ARCH_MSM_CORTEXMP
 	select MSM_SMP
@@ -424,7 +425,6 @@
 
 config  ARCH_MSM_CORTEX_A5
 	bool
-	select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
 
 config ARCH_MSM7X27A
 	bool
@@ -927,7 +927,7 @@
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
 	default "0x10000000" if ARCH_FSM9XXX
-	default "0x20200000" if ARCH_MSM9625
+	default "0x00200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
 	default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
 	default "0x20000000" if ARCH_QSD8X50
@@ -1903,13 +1903,13 @@
 
 config MSM_PIL_MODEM
 	tristate "Modem (ARM11) Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down ARM11 Modem processors.
 
 config MSM_PIL_QDSP6V3
 	tristate "QDSP6v3 (Hexagon) Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down QDSP6v3 processors (hexagon).
 	  The QDSP6 is a low power DSP used in audio software applications.
@@ -1945,7 +1945,7 @@
 
 config MSM_PIL_RIVA
 	tristate "RIVA (WCNSS) Boot Support"
-	depends on MSM_PIL
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down the RIVA processor (WCNSS).
 	  Riva is the wireless subsystem processor used in bluetooth, wireless
@@ -1984,8 +1984,8 @@
 	  Venus is the Video subsystem processor used for video codecs.
 
 config MSM_PIL_GSS
-	tristate "GSS (Coretx A5) Boot Support"
-	depends on MSM_PIL
+	tristate "GSS (Cortex A5) Boot Support"
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
 	  Support for booting and shutting down Cortex A5 processors which run
 	  GPS subsystem firmware.
@@ -2018,22 +2018,6 @@
 	 lpass hardware watchdog interrupt lines and plugs into the subsystem
 	 restart and PIL drivers. For MSM9615, it only supports a full chip reset.
 
-config MSM_WCNSS_SSR_8960
-	tristate "MSM 8960 WCNSS restart module"
-	depends on (ARCH_MSM8960)
-	help
-	 This option enables the WCNSS restart module for MSM8960, which
-	 monitors WCNSS hardware watchdog interrupt lines and plugs WCNSS
-	 into the subsystem restart framework.
-
-config MSM_GSS_SSR_8064
-	bool "MSM 8064 GSS restart driver"
-	depends on (ARCH_APQ8064)
-	help
-	 This option enables the gps subsystem restart driver for APQ8064, which monitors
-	 gss hardware watchdog interrupt lines and plugs into the subsystem
-	 restart and PIL drivers.
-
 config MSM_MODEM_SSR_8974
 	bool "MSM 8974 Modem restart driver"
 	depends on (ARCH_MSM8974)
@@ -2643,4 +2627,12 @@
 	 such as display backlight, vreg pin-ctrl, smps clock over the RPC
 	 interface. This support is required for MSMs on which the APPS
 	 does not have a direct access to the PMIC.
+
+config MSM_ENABLE_WDOG_DEBUG_CONTROL
+	bool "MSM Watchdog driver to disable debug Image"
+	help
+	 This driver supports the configuration of the GCC_WDOG_DEBUG register
+	 used to control debug image.
+	 This support is currently required for MSM8974 to disable debug image
+	 on PS HOLD reset
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3c44a06..7dece76 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -65,6 +65,8 @@
 $(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
 	$(call if_changed,mkrpcsym)
 
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
+
 obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
 obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
 obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
@@ -96,7 +98,6 @@
 ifdef CONFIG_DEBUG_FS
 obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
 endif
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
 obj-y += socinfo.o
 ifndef CONFIG_ARCH_MSM8960
 ifndef CONFIG_ARCH_MSM8X60
@@ -194,15 +195,12 @@
 	obj-y += subsystem_notif.o
 	obj-y += subsystem_restart.o
 	obj-y += ramdump.o
-	obj-$(CONFIG_ARCH_MSM8X60) += modem-8660.o lpass-8660.o
 endif
 obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
 obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
 obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
 obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
 obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
-obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
-obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
 
 ifdef CONFIG_CPU_IDLE
 	obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
@@ -274,7 +272,7 @@
 obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
-obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
+obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
 obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
@@ -350,7 +348,7 @@
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
 
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
-obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o
+obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o msm_mpdecision.o
 obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
 obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o
 obj-$(CONFIG_BT_MSM_PINTEST)  += btpintest.o
@@ -383,6 +381,7 @@
 obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o
 obj-$(CONFIG_MSM_RPC_PMAPP) += rpc_pmapp.o
 
+obj-$(CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL) += wdog_debug.o
 
 ifdef CONFIG_MSM_CPR
 obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 526616a..9234b2c 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -52,7 +52,7 @@
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
 
 # MSM9625
-   zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x20208000
+   zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x00208000
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 6788cbe..5c4a923 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -719,6 +719,7 @@
 				 */
 				clk_enable(pll_clk[backup_s->pll].clk);
 				acpuclk_set_div(backup_s);
+				update_jiffies(cpu, backup_s->lpj);
 			}
 			/* Make sure PLL4 is off before reprogramming */
 			if ((plls_enabled & (1 << tgt_s->pll))) {
@@ -736,6 +737,7 @@
 				 */
 				clk_enable(pll_clk[backup_s->pll].clk);
 				acpuclk_set_div(backup_s);
+				update_jiffies(cpu, backup_s->lpj);
 			}
 		}
 
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 06c2579..d10211bc 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -18,6 +18,7 @@
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 
+#include "mach/socinfo.h"
 #include "acpuclock.h"
 #include "acpuclock-krait.h"
 
@@ -44,6 +45,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -54,6 +56,7 @@
 		.hfpll_phys_base = 0x00903240,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -64,6 +67,7 @@
 		.hfpll_phys_base = 0x00903280,
 		.aux_clk_sel_phys = 0x020A8014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x6501,
 		.vreg[VREG_CORE] = { "krait2", 1300000 },
 		.vreg[VREG_MEM]  = { "krait2_mem", 1150000 },
@@ -74,6 +78,7 @@
 		.hfpll_phys_base = 0x009032C0,
 		.aux_clk_sel_phys = 0x020B8014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x7501,
 		.vreg[VREG_CORE] = { "krait3", 1300000 },
 		.vreg[VREG_MEM]  = { "krait3_mem", 1150000 },
@@ -84,11 +89,16 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
 	},
 };
 
+/*
+ * The correct maximum rate for 8064ab in 600 MHZ.
+ * We rely on the RPM rounding requests up here.
+*/
 static struct msm_bus_paths bw_level_tbl[] __initdata = {
 	[0] =  BW_MBPS(640), /* At least  80 MHz on bus. */
 	[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
@@ -105,110 +115,191 @@
 	.name = "acpuclk-8064",
 };
 
-static struct l2_level l2_freq_tbl[] __initdata __initdata = {
-	[0]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
-	[1]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
-	[2]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
-	[3]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
-	[4]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
-	[5]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
-	[6]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
-	[7]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
-	[8]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
-	[9]  = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
-	[10] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
-	[11] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 5 },
-	[12] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
-	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 5 },
-	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
-	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 5 },
+static struct l2_level l2_freq_tbl[] __initdata = {
+	[0]  = { {  384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
+	[1]  = { {  432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
+	[2]  = { {  486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
+	[3]  = { {  540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
+	[4]  = { {  594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
+	[5]  = { {  648000, HFPLL, 1, 0x18 }, 1050000, 1050000, 4 },
+	[6]  = { {  702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
+	[7]  = { {  756000, HFPLL, 1, 0x1C }, 1150000, 1150000, 4 },
+	[8]  = { {  810000, HFPLL, 1, 0x1E }, 1150000, 1150000, 4 },
+	[9]  = { {  864000, HFPLL, 1, 0x20 }, 1150000, 1150000, 4 },
+	[10] = { {  918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 5 },
+	[11] = { {  972000, HFPLL, 1, 0x24 }, 1150000, 1150000, 5 },
+	[12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
+	[13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 5 },
+	[14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
+	[15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 5 },
+	/* L2 Level 16 is for 8064ab only */
+	[16] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 5 },
 	{ }
 };
 
-static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000 },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   975000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   975000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),  1000000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1000000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1025000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1025000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(6),  1075000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(6),  1075000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(6),  1100000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1100000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1125000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
+static struct acpu_level tbl_slow[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000 },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   950000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   950000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   975000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   975000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(6),  1025000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(6),  1025000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(6),  1050000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1050000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1075000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
+static struct acpu_level tbl_nom[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   925000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   950000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),   975000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   975000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),  1025000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1025000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1050000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1050000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1075000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1075000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1175000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1200000 },
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   850000 },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   875000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   875000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   900000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   925000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   925000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(6),   975000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(6),   975000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(6),  1000000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1000000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1025000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
+static struct acpu_level tbl_fast[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   850000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   925000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),   975000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   975000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1000000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1000000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1025000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1025000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1100000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1150000 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
-[PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
-/* TODO: update the faster table when data is available */
-[PVS_FASTER]  = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct acpu_level tbl_slow_1p7[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
+	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_slow_2p0[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
+	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1250000 },
+	{ 1, {  1836000, HFPLL, 1, 0x44 }, L2(15), 1250000 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 },
+	{ 1, {  1944000, HFPLL, 1, 0x48 }, L2(15), 1250000 },
+	{ 1, {  1998000, HFPLL, 1, 0x4A }, L2(15), 1250000 },
+	{ 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+	[0][PVS_SLOW]    = {tbl_slow, sizeof(tbl_slow),     0 },
+	[0][PVS_NOMINAL] = {tbl_nom,  sizeof(tbl_nom),  25000 },
+	[0][PVS_FAST]    = {tbl_fast, sizeof(tbl_fast), 25000 },
+	[0][PVS_FASTER]  = {tbl_fast, sizeof(tbl_fast), 25000 },
+
+	[1][0] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+	[1][1] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+	[1][2] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+	[1][3] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+	[1][4] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+	[1][5] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+	[1][6] = { tbl_slow_1p7, sizeof(tbl_slow_1p7),     0 },
+
+	[2][0] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
+	[2][1] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
+	[2][2] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
+	[2][3] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
+	[2][4] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
+	[2][5] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
+	[2][6] = { tbl_slow_2p0, sizeof(tbl_slow_2p0),     0 },
 };
 
 static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
@@ -225,6 +316,12 @@
 
 static int __init acpuclk_8064_probe(struct platform_device *pdev)
 {
+	if (cpu_is_apq8064ab() ||
+		SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+		acpuclk_8064_params.hfpll_data->low_vdd_l_max = 37;
+		acpuclk_8064_params.hfpll_data->nom_vdd_l_max = 74;
+	}
+
 	return acpuclk_krait_init(&pdev->dev, &acpuclk_8064_params);
 }
 
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index 9e6662d..ac29cac 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -50,6 +50,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -60,6 +61,7 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -70,6 +72,7 @@
 		.hfpll_phys_base = 0x00903400,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
 	},
@@ -92,42 +95,42 @@
 
 /* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
-	[1]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 1 },
-	[2]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 1 },
-	[3]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
-	[4]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
-	[5]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 2 },
-	[6]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 3 },
-	[7]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 3 },
-	[8]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 3 },
-	[9]  = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
-	[10] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
-	[11] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
+	[0]  = { {  384000, PLL_8, 0, 0x00 },  LVL_NOM, 1050000, 1 },
+	[1]  = { {  432000, HFPLL, 2, 0x20 },  LVL_NOM, 1050000, 1 },
+	[2]  = { {  486000, HFPLL, 2, 0x24 },  LVL_NOM, 1050000, 1 },
+	[3]  = { {  540000, HFPLL, 2, 0x28 },  LVL_NOM, 1050000, 2 },
+	[4]  = { {  594000, HFPLL, 1, 0x16 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  648000, HFPLL, 1, 0x18 },  LVL_NOM, 1050000, 2 },
+	[6]  = { {  702000, HFPLL, 1, 0x1A },  LVL_NOM, 1050000, 3 },
+	[7]  = { {  756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 3 },
+	[8]  = { {  810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 3 },
+	[9]  = { {  864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[10] = { {  918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 4 },
+	[11] = { {  972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 4 },
 	{ }
 };
 
 /* TODO: Update core voltages when data is available. */
 static struct acpu_level acpu_freq_tbl[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(4),   925000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(4),   925000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(4),   937500 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(4),   962500 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(8),   987500 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(8),  1000000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(8),  1025000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(8),  1062500 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(11), 1100000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(4),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(4),   925000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(4),   937500 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(4),   962500 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(8),   987500 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(8),  1000000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(8),  1025000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(8),  1062500 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(11), 1062500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(11), 1087500 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(11), 1100000 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-	[PVS_SLOW]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl),     0 },
-	[PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
-	[PVS_FAST]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+	[0][PVS_SLOW]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl),     0 },
+	[0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
+	[0][PVS_FAST]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8627_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index b8ca865..e46599a 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -50,6 +50,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -61,6 +62,7 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -72,6 +74,7 @@
 		.hfpll_phys_base = 0x00903400,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
 		.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
@@ -83,6 +86,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -93,6 +97,7 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -103,6 +108,7 @@
 		.hfpll_phys_base = 0x00903400,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
 	},
@@ -128,89 +134,89 @@
 
 /* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
-	[1]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 2 },
-	[2]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 2 },
-	[3]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
-	[4]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
-	[5]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 4 },
-	[6]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 4 },
-	[7]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
-	[8]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
-	[9]  = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
-	[10] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
-	[11] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
-	[12] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
-	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
-	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
-	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+	[0]  = { {  384000, PLL_8, 0, 0x00 },  LVL_NOM, 1050000, 1 },
+	[1]  = { {  432000, HFPLL, 2, 0x20 },  LVL_NOM, 1050000, 2 },
+	[2]  = { {  486000, HFPLL, 2, 0x24 },  LVL_NOM, 1050000, 2 },
+	[3]  = { {  540000, HFPLL, 2, 0x28 },  LVL_NOM, 1050000, 2 },
+	[4]  = { {  594000, HFPLL, 1, 0x16 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  648000, HFPLL, 1, 0x18 },  LVL_NOM, 1050000, 4 },
+	[6]  = { {  702000, HFPLL, 1, 0x1A },  LVL_NOM, 1050000, 4 },
+	[7]  = { {  756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
+	[8]  = { {  810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
+	[9]  = { {  864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[10] = { {  918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 7 },
+	[11] = { {  972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 7 },
+	[12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 7 },
+	[13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 7 },
+	[14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 7 },
+	[15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 7 },
 	{ }
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   975000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),  1000000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(5),  1025000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(10), 1075000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(10), 1100000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(10), 1125000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
+	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   925000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   950000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   950000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),   975000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),   975000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(5),  1000000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(5),  1000000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(10), 1050000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(10), 1050000 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(10), 1075000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(10), 1075000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(10), 1100000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1100000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1150000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1150000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1175000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   950000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   950000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   975000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   975000 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1000000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1000000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
+	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
+	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   900000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),   925000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),   925000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(5),   950000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(5),   950000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(10), 1000000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(10), 1000000 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(10), 1025000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(10), 1025000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(10), 1050000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1050000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1100000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1100000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1125000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   900000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   900000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   925000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   925000 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),   950000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),   950000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
+	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
+	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
-[PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
+[0][PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8930_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index d589f1a..9d2b6fc 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -50,6 +50,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -60,6 +61,7 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -70,6 +72,7 @@
 		.hfpll_phys_base = 0x00903400,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
 	},
@@ -95,101 +98,101 @@
 
 /* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
-	[1]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 2 },
-	[2]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 2 },
-	[3]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
-	[4]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
-	[5]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 4 },
-	[6]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 4 },
-	[7]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
-	[8]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
-	[9]  = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
-	[10] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
-	[11] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
-	[12] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
-	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
-	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
-	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+	[0]  = { {  384000, PLL_8, 0, 0x00 },  LVL_NOM, 1050000, 1 },
+	[1]  = { {  432000, HFPLL, 2, 0x20 },  LVL_NOM, 1050000, 2 },
+	[2]  = { {  486000, HFPLL, 2, 0x24 },  LVL_NOM, 1050000, 2 },
+	[3]  = { {  540000, HFPLL, 2, 0x28 },  LVL_NOM, 1050000, 2 },
+	[4]  = { {  594000, HFPLL, 1, 0x16 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  648000, HFPLL, 1, 0x18 },  LVL_NOM, 1050000, 4 },
+	[6]  = { {  702000, HFPLL, 1, 0x1A },  LVL_NOM, 1050000, 4 },
+	[7]  = { {  756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
+	[8]  = { {  810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
+	[9]  = { {  864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[10] = { {  918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 7 },
+	[11] = { {  972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 7 },
+	[12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 7 },
+	[13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 7 },
+	[14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 7 },
+	[15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 7 },
 	{ }
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   975000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),  1000000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(5),  1025000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(10), 1075000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(10), 1100000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(10), 1125000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
+	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   925000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   950000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   950000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),   975000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),   975000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(5),  1000000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(5),  1000000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(10), 1050000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(10), 1050000 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(10), 1075000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(10), 1075000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(10), 1100000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1100000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1150000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1150000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1175000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1175000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1200000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1200000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1212500 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   950000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   950000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   975000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   975000 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1000000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1000000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
+	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
+	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1175000 },
+	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1200000 },
+	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1212500 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   900000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),   925000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),   925000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(5),   950000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(5),   950000 },
-	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(10), 1000000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(10), 1000000 },
-	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(10), 1025000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(10), 1025000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(10), 1050000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1050000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1100000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1100000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1125000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1125000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1150000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1150000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1162500 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   900000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   900000 },
+	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   925000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   925000 },
+	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),   950000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),   950000 },
+	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
+	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
+	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
+	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
+	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
+	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
+	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1162500 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
-[PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
+[0][PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8930aa_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index e16c6b6..d7d3edd 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -44,6 +44,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -55,6 +56,7 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -66,6 +68,7 @@
 		.hfpll_phys_base = 0x00903400,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
 		.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
@@ -90,112 +93,112 @@
 };
 
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
-	[1]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
-	[2]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
-	[3]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
-	[4]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
-	[5]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
-	[6]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
-	[7]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
-	[8]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
-	[9]  = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
-	[10] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 6 },
-	[11] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 6 },
-	[12] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 6 },
-	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 6 },
-	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 6 },
-	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 6 },
-	[16] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 6 },
-	[17] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 6 },
-	[18] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
+	[0]  = { {  384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
+	[1]  = { {  432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
+	[2]  = { {  486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
+	[3]  = { {  540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
+	[4]  = { {  594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
+	[5]  = { {  648000, HFPLL, 1, 0x18 }, 1050000, 1050000, 4 },
+	[6]  = { {  702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
+	[7]  = { {  756000, HFPLL, 1, 0x1C }, 1150000, 1150000, 4 },
+	[8]  = { {  810000, HFPLL, 1, 0x1E }, 1150000, 1150000, 4 },
+	[9]  = { {  864000, HFPLL, 1, 0x20 }, 1150000, 1150000, 4 },
+	[10] = { {  918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 6 },
+	[11] = { {  972000, HFPLL, 1, 0x24 }, 1150000, 1150000, 6 },
+	[12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 6 },
+	[13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 6 },
+	[14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 6 },
+	[15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 6 },
+	[16] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 6 },
+	[17] = { { 1296000, HFPLL, 1, 0x30 }, 1150000, 1150000, 6 },
+	[18] = { { 1350000, HFPLL, 1, 0x32 }, 1150000, 1150000, 6 },
 	{ }
 };
 
 #define AVS(x) .avsdscr_setting = (x)
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000, AVS(0x40001F) },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   975000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   975000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),  1000000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1000000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1025000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1025000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(6),  1075000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(6),  1075000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(6),  1100000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1100000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1125000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1175000, AVS(0x400015) },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1175000, AVS(0x400015) },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1200000, AVS(0x400015) },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1200000, AVS(0x400015) },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1225000, AVS(0x400015) },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1225000, AVS(0x400015) },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1237500, AVS(0x400015) },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1237500, AVS(0x100018) },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1250000, AVS(0x400012) },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000, AVS(0x40001F) },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(18), 1175000, AVS(0x400015) },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(18), 1175000, AVS(0x400015) },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(18), 1200000, AVS(0x400015) },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(18), 1200000, AVS(0x400015) },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(18), 1225000, AVS(0x400015) },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(18), 1225000, AVS(0x400015) },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(18), 1237500, AVS(0x400015) },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(18), 1237500, AVS(0x100018) },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(18), 1250000, AVS(0x400012) },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   900000, AVS(0x40007F) },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   950000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   950000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   975000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   975000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(6),  1025000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(6),  1025000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(6),  1050000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1050000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1075000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1125000, AVS(0x400015) },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1125000, AVS(0x400015) },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1150000, AVS(0x400015) },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1150000, AVS(0x400015) },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1175000, AVS(0x400015) },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1175000, AVS(0x400015) },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1187500, AVS(0x400015) },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1187500, AVS(0x100018) },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1200000, AVS(0x400012) },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000, AVS(0x40007F) },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   925000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   950000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),   975000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   975000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),  1025000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1025000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1050000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1050000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1075000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1075000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(18), 1125000, AVS(0x400015) },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(18), 1125000, AVS(0x400015) },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(18), 1150000, AVS(0x400015) },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(18), 1150000, AVS(0x400015) },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(18), 1175000, AVS(0x400015) },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(18), 1175000, AVS(0x400015) },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(18), 1187500, AVS(0x400015) },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(18), 1187500, AVS(0x100018) },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(18), 1200000, AVS(0x400012) },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   850000, AVS(0x4000FF) },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   875000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   875000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   900000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   925000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   925000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(6),   975000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(6),   975000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(6),  1000000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1000000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1025000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1125000, AVS(0x400012) },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1137500, AVS(0x400012) },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1137500, AVS(0x400012) },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1150000, AVS(0x400012) },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   850000, AVS(0x4000FF) },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(6),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(6),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(6),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   925000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(6),   975000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   975000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(6),  1000000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1000000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(6),  1025000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1025000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(18), 1125000, AVS(0x400012) },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(18), 1137500, AVS(0x400012) },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(18), 1137500, AVS(0x400012) },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(18), 1150000, AVS(0x400012) },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
-[PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
+[0][PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8960_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 628e1ba..ae1cd7b 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -44,6 +44,7 @@
 		.hfpll_phys_base = 0x00903200,
 		.aux_clk_sel_phys = 0x02088014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x4501,
 		.vreg[VREG_CORE] = { "krait0", 1300000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
@@ -55,6 +56,7 @@
 		.hfpll_phys_base = 0x00903300,
 		.aux_clk_sel_phys = 0x02098014,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x5501,
 		.vreg[VREG_CORE] = { "krait1", 1300000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
@@ -66,6 +68,7 @@
 		.hfpll_phys_base = 0x00903400,
 		.aux_clk_sel_phys = 0x02011028,
 		.aux_clk_sel = 3,
+		.sec_clk_sel = 2,
 		.l2cpmr_iaddr = 0x0500,
 		.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
 		.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
@@ -89,53 +92,53 @@
 };
 
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
-	[1]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
-	[2]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
-	[3]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
-	[4]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1050000, 1050000, 4 },
-	[5]  = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
-	[6]  = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
-	[7]  = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
-	[8]  = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 5 },
-	[9]  = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 5 },
+	[0]  = { {  384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
+	[1]  = { {  486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
+	[2]  = { {  594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
+	[3]  = { {  702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
+	[4]  = { {  810000, HFPLL, 1, 0x1E }, 1050000, 1050000, 4 },
+	[5]  = { {  918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 5 },
+	[6]  = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
+	[7]  = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
+	[8]  = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 5 },
+	[9]  = { { 1350000, HFPLL, 1, 0x32 }, 1150000, 1150000, 5 },
 	{ }
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000 },
-	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(3),   975000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(3),   975000 },
-	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(3),  1000000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(3),  1000000 },
-	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(3),  1025000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(3),  1025000 },
-	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(3),  1075000 },
-	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(3),  1075000 },
-	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(3),  1100000 },
-	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(3),  1100000 },
-	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(3),  1125000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(3),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(9),  1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(9),  1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(9),  1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(9),  1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(9),  1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(9),  1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(9),  1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(9),  1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(9),  1250000 },
-	{ 1, {  1566000, HFPLL, 1, 0, 0x3A }, L2(9),  1250000 },
-	{ 1, {  1620000, HFPLL, 1, 0, 0x3C }, L2(9),  1250000 },
-	{ 1, {  1674000, HFPLL, 1, 0, 0x3E }, L2(9),  1250000 },
-	{ 1, {  1728000, HFPLL, 1, 0, 0x40 }, L2(9),  1250000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(3),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(3),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(3),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(3),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(3),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(3),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(9),  1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(9),  1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(9),  1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(9),  1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(9),  1250000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1250000 },
+	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(9),  1250000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1250000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1250000 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
-[PVS_FAST]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+[0][PVS_FAST]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
 };
 
 static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index ee2ca45..098f854 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -36,8 +36,8 @@
 	.has_user_reg = true,
 	.user_offset = 0x10,
 	.config_offset = 0x14,
-	/* TODO: Verify magic numbers when final values are available. */
 	.user_val = 0x8,
+	.user_vco_mask = BIT(20),
 	.config_val = 0x04D0405D,
 	.low_vco_l_max = 65,
 	.low_vdd_l_max = 52,
@@ -52,6 +52,7 @@
 	[CPU0] = {
 		.hfpll_phys_base = 0xF908A000,
 		.l2cpmr_iaddr = 0x4501,
+		.sec_clk_sel = 2,
 		.vreg[VREG_CORE] = { "krait0",     1050000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH },
@@ -61,6 +62,7 @@
 	[CPU1] = {
 		.hfpll_phys_base = 0xF909A000,
 		.l2cpmr_iaddr = 0x5501,
+		.sec_clk_sel = 2,
 		.vreg[VREG_CORE] = { "krait1",     1050000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH },
@@ -70,6 +72,7 @@
 	[CPU2] = {
 		.hfpll_phys_base = 0xF90AA000,
 		.l2cpmr_iaddr = 0x6501,
+		.sec_clk_sel = 2,
 		.vreg[VREG_CORE] = { "krait2",     1050000 },
 		.vreg[VREG_MEM]  = { "krait2_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait2_dig", LVL_HIGH },
@@ -79,6 +82,7 @@
 	[CPU3] = {
 		.hfpll_phys_base = 0xF90BA000,
 		.l2cpmr_iaddr = 0x7501,
+		.sec_clk_sel = 2,
 		.vreg[VREG_CORE] = { "krait3",     1050000 },
 		.vreg[VREG_MEM]  = { "krait3_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait3_dig", LVL_HIGH },
@@ -88,6 +92,7 @@
 	[L2] = {
 		.hfpll_phys_base = 0xF9016000,
 		.l2cpmr_iaddr = 0x0500,
+		.sec_clk_sel = 2,
 		.vreg[VREG_HFPLL_A] = { "l2_hfpll_a", 2150000 },
 		.vreg[VREG_HFPLL_B] = { "l2_hfpll_b", 1800000 },
 	},
@@ -108,67 +113,67 @@
 };
 
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_LOW,   950000, 0 },
-	[1]  = { {  384000, HFPLL, 2, 0,  40 }, LVL_NOM,   950000, 1 },
-	[2]  = { {  460800, HFPLL, 2, 0,  48 }, LVL_NOM,   950000, 1 },
-	[3]  = { {  537600, HFPLL, 1, 0,  28 }, LVL_NOM,   950000, 2 },
-	[4]  = { {  576000, HFPLL, 1, 0,  30 }, LVL_NOM,   950000, 2 },
-	[5]  = { {  652800, HFPLL, 1, 0,  34 }, LVL_NOM,   950000, 2 },
-	[6]  = { {  729600, HFPLL, 1, 0,  38 }, LVL_NOM,   950000, 2 },
-	[7]  = { {  806400, HFPLL, 1, 0,  42 }, LVL_NOM,   950000, 2 },
-	[8]  = { {  883200, HFPLL, 1, 0,  46 }, LVL_HIGH, 1050000, 2 },
-	[9]  = { {  960000, HFPLL, 1, 0,  50 }, LVL_HIGH, 1050000, 2 },
-	[10] = { { 1036800, HFPLL, 1, 0,  54 }, LVL_HIGH, 1050000, 3 },
-	[11] = { { 1113600, HFPLL, 1, 0,  58 }, LVL_HIGH, 1050000, 3 },
-	[12] = { { 1190400, HFPLL, 1, 0,  62 }, LVL_HIGH, 1050000, 3 },
-	[13] = { { 1267200, HFPLL, 1, 0,  66 }, LVL_HIGH, 1050000, 3 },
-	[14] = { { 1344000, HFPLL, 1, 0,  70 }, LVL_HIGH, 1050000, 3 },
-	[15] = { { 1420800, HFPLL, 1, 0,  74 }, LVL_HIGH, 1050000, 3 },
-	[16] = { { 1497600, HFPLL, 1, 0,  78 }, LVL_HIGH, 1050000, 3 },
-	[17] = { { 1574400, HFPLL, 1, 0,  82 }, LVL_HIGH, 1050000, 3 },
-	[18] = { { 1651200, HFPLL, 1, 0,  86 }, LVL_HIGH, 1050000, 3 },
-	[19] = { { 1728000, HFPLL, 1, 0,  90 }, LVL_HIGH, 1050000, 3 },
-	[20] = { { 1804800, HFPLL, 1, 0,  94 }, LVL_HIGH, 1050000, 3 },
-	[21] = { { 1881600, HFPLL, 1, 0,  98 }, LVL_HIGH, 1050000, 3 },
-	[22] = { { 1958400, HFPLL, 1, 0, 102 }, LVL_HIGH, 1050000, 3 },
-	[23] = { { 2035200, HFPLL, 1, 0, 106 }, LVL_HIGH, 1050000, 3 },
-	[24] = { { 2112000, HFPLL, 1, 0, 110 }, LVL_HIGH, 1050000, 3 },
-	[25] = { { 2188800, HFPLL, 1, 0, 114 }, LVL_HIGH, 1050000, 3 },
+	[0]  = { {  300000, PLL_0, 0,   0 }, LVL_LOW,   950000, 0 },
+	[1]  = { {  384000, HFPLL, 2,  40 }, LVL_NOM,   950000, 1 },
+	[2]  = { {  460800, HFPLL, 2,  48 }, LVL_NOM,   950000, 1 },
+	[3]  = { {  537600, HFPLL, 1,  28 }, LVL_NOM,   950000, 2 },
+	[4]  = { {  576000, HFPLL, 1,  30 }, LVL_NOM,   950000, 2 },
+	[5]  = { {  652800, HFPLL, 1,  34 }, LVL_NOM,   950000, 2 },
+	[6]  = { {  729600, HFPLL, 1,  38 }, LVL_NOM,   950000, 2 },
+	[7]  = { {  806400, HFPLL, 1,  42 }, LVL_NOM,   950000, 2 },
+	[8]  = { {  883200, HFPLL, 1,  46 }, LVL_HIGH, 1050000, 2 },
+	[9]  = { {  960000, HFPLL, 1,  50 }, LVL_HIGH, 1050000, 2 },
+	[10] = { { 1036800, HFPLL, 1,  54 }, LVL_HIGH, 1050000, 3 },
+	[11] = { { 1113600, HFPLL, 1,  58 }, LVL_HIGH, 1050000, 3 },
+	[12] = { { 1190400, HFPLL, 1,  62 }, LVL_HIGH, 1050000, 3 },
+	[13] = { { 1267200, HFPLL, 1,  66 }, LVL_HIGH, 1050000, 3 },
+	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 3 },
+	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 3 },
+	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 3 },
+	[17] = { { 1574400, HFPLL, 1,  82 }, LVL_HIGH, 1050000, 3 },
+	[18] = { { 1651200, HFPLL, 1,  86 }, LVL_HIGH, 1050000, 3 },
+	[19] = { { 1728000, HFPLL, 1,  90 }, LVL_HIGH, 1050000, 3 },
+	[20] = { { 1804800, HFPLL, 1,  94 }, LVL_HIGH, 1050000, 3 },
+	[21] = { { 1881600, HFPLL, 1,  98 }, LVL_HIGH, 1050000, 3 },
+	[22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 3 },
+	[23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 3 },
+	[24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 3 },
+	[25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 3 },
 	{ }
 };
 
 static struct acpu_level acpu_freq_tbl[] __initdata = {
-	{ 1, {  300000, PLL_0, 0, 2,   0 }, L2(0),   950000, 3200000 },
-	{ 1, {  384000, HFPLL, 2, 0,  40 }, L2(3),   950000, 3200000 },
-	{ 1, {  460800, HFPLL, 2, 0,  48 }, L2(3),   950000, 3200000 },
-	{ 1, {  537600, HFPLL, 1, 0,  28 }, L2(5),   950000, 3200000 },
-	{ 1, {  576000, HFPLL, 1, 0,  30 }, L2(5),   950000, 3200000 },
-	{ 1, {  652800, HFPLL, 1, 0,  34 }, L2(5),   950000, 3200000 },
-	{ 1, {  729600, HFPLL, 1, 0,  38 }, L2(5),   950000, 3200000 },
-	{ 1, {  806400, HFPLL, 1, 0,  42 }, L2(7),   950000, 3200000 },
-	{ 1, {  883200, HFPLL, 1, 0,  46 }, L2(7),   950000, 3200000 },
-	{ 1, {  960000, HFPLL, 1, 0,  50 }, L2(7),   950000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1, 0,  54 }, L2(7),   950000, 3200000 },
-	{ 1, { 1113600, HFPLL, 1, 0,  58 }, L2(12), 1050000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1, 0,  62 }, L2(12), 1050000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1, 0,  66 }, L2(12), 1050000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1, 0,  70 }, L2(15), 1050000, 3200000 },
-	{ 1, { 1420800, HFPLL, 1, 0,  74 }, L2(15), 1050000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1, 0,  78 }, L2(16), 1050000, 3200000 },
-	{ 0, { 1574400, HFPLL, 1, 0,  82 }, L2(20), 1050000, 3200000 },
-	{ 0, { 1651200, HFPLL, 1, 0,  86 }, L2(20), 1050000, 3200000 },
-	{ 0, { 1728000, HFPLL, 1, 0,  90 }, L2(20), 1050000, 3200000 },
-	{ 0, { 1804800, HFPLL, 1, 0,  94 }, L2(25), 1050000, 3200000 },
-	{ 0, { 1881600, HFPLL, 1, 0,  98 }, L2(25), 1050000, 3200000 },
-	{ 0, { 1958400, HFPLL, 1, 0, 102 }, L2(25), 1050000, 3200000 },
-	{ 0, { 1996800, HFPLL, 1, 0, 104 }, L2(25), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   950000, 3200000 },
+	{ 1, {  384000, HFPLL, 2,  40 }, L2(3),   950000, 3200000 },
+	{ 1, {  460800, HFPLL, 2,  48 }, L2(3),   950000, 3200000 },
+	{ 1, {  537600, HFPLL, 1,  28 }, L2(5),   950000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(5),   950000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(5),   950000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(5),   950000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(7),   950000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(7),   950000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(7),   950000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(7),   950000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(12), 1050000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(12), 1050000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(12), 1050000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(15), 1050000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(15), 1050000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1050000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(20), 1050000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(20), 1050000, 3200000 },
+	{ 0, { 1728000, HFPLL, 1,  90 }, L2(20), 1050000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(25), 1050000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(25), 1050000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(25), 1050000, 3200000 },
+	{ 0, { 1996800, HFPLL, 1, 104 }, L2(25), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
-static struct pvs_table pvs_tables[NUM_PVS]  __initdata = {
-	[PVS_SLOW]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
-	[PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl)  },
-	[PVS_FAST]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS]  __initdata = {
+	[0][PVS_SLOW]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+	[0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+	[0][PVS_FAST]    = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
 };
 
 static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 2951c1a..57c4411 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -42,8 +42,8 @@
 #define PRI_SRC_SEL_SEC_SRC	0
 #define PRI_SRC_SEL_HFPLL	1
 #define PRI_SRC_SEL_HFPLL_DIV2	2
-#define SEC_SRC_SEL_L2PLL	1
-#define SEC_SRC_SEL_AUX		2
+
+#define SECCLKAGD		BIT(4)
 
 static DEFINE_MUTEX(driver_lock);
 static DEFINE_SPINLOCK(l2_lock);
@@ -79,14 +79,24 @@
 }
 
 /* Select a source on the secondary MUX. */
-static void set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
+static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
 {
 	u32 regval;
 
+	/* 8064 Errata: disable sec_src clock gating during switch. */
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval |= SECCLKAGD;
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Program the MUX */
 	regval &= ~(0x3 << 2);
 	regval |= ((sec_src_sel & 0x3) << 2);
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* 8064 Errata: re-enabled sec_src clock gating. */
+	regval &= ~SECCLKAGD;
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
 	/* Wait for switch to complete. */
 	mb();
 	udelay(1);
@@ -220,7 +230,6 @@
 		 * Move to an always-on source running at a frequency
 		 * that does not require an elevated CPU voltage.
 		 */
-		set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
 		set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
 
 		/* Re-program HFPLL. */
@@ -231,15 +240,12 @@
 		/* Move to HFPLL. */
 		set_pri_clk_src(sc, tgt_s->pri_src_sel);
 	} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
-		set_sec_clk_src(sc, tgt_s->sec_src_sel);
 		set_pri_clk_src(sc, tgt_s->pri_src_sel);
 		hfpll_disable(sc, false);
 	} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
 		hfpll_set_rate(sc, tgt_s);
 		hfpll_enable(sc, false);
 		set_pri_clk_src(sc, tgt_s->pri_src_sel);
-	} else {
-		set_sec_clk_src(sc, tgt_s->sec_src_sel);
 	}
 
 	sc->cur_speed = tgt_s;
@@ -709,7 +715,7 @@
 	}
 
 	/* Switch away from the HFPLL while it's re-initialized. */
-	set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+	set_sec_clk_src(sc, sc->sec_clk_sel);
 	set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
 	hfpll_init(sc, tgt_s);
 
@@ -719,7 +725,6 @@
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 
 	/* Switch to the target clock source. */
-	set_sec_clk_src(sc, tgt_s->sec_src_sel);
 	set_pri_clk_src(sc, tgt_s->pri_src_sel);
 	sc->cur_speed = tgt_s;
 
@@ -730,7 +735,6 @@
 					  struct scalable *sc)
 {
 	s->pri_src_sel = get_l2_indirect_reg(sc->l2cpmr_iaddr) & 0x3;
-	s->sec_src_sel = (get_l2_indirect_reg(sc->l2cpmr_iaddr) >> 2) & 0x3;
 	s->pll_l_val = readl_relaxed(sc->hfpll_base + drv.hfpll_data->l_offset);
 }
 
@@ -738,7 +742,6 @@
 				  const struct core_speed *s2)
 {
 	return (s1->pri_src_sel == s2->pri_src_sel &&
-		s1->sec_src_sel == s2->sec_src_sel &&
 		s1->pll_l_val == s2->pll_l_val);
 }
 
@@ -943,58 +946,68 @@
 	}
 }
 
-static int __init select_freq_plan(u32 pte_efuse_phys)
+static int __init get_speed_bin(u32 pte_efuse)
+{
+	uint32_t speed_bin;
+
+	speed_bin = pte_efuse & 0xF;
+	if (speed_bin == 0xF)
+		speed_bin = (pte_efuse >> 4) & 0xF;
+
+	if (speed_bin == 0xF) {
+		speed_bin = 0;
+		dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n", speed_bin);
+	} else {
+		dev_info(drv.dev, "SPEED BIN: %d\n", speed_bin);
+	}
+
+	return speed_bin;
+}
+
+static int __init get_pvs_bin(u32 pte_efuse)
+{
+	uint32_t pvs_bin;
+
+	pvs_bin = (pte_efuse >> 10) & 0x7;
+	if (pvs_bin == 0x7)
+		pvs_bin = (pte_efuse >> 13) & 0x7;
+
+	if (pvs_bin == 0x7) {
+		pvs_bin = 0;
+		dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n", pvs_bin);
+	} else {
+		dev_info(drv.dev, "ACPU PVS: %d\n", pvs_bin);
+	}
+
+	return pvs_bin;
+}
+
+static struct pvs_table * __init select_freq_plan(u32 pte_efuse_phys,
+			struct pvs_table (*pvs_tables)[NUM_PVS])
 {
 	void __iomem *pte_efuse;
-	u32 pte_efuse_val, pvs, tbl_idx;
-	char *pvs_names[] = { "Slow", "Nominal", "Fast", "Faster", "Unknown" };
+	u32 pte_efuse_val, tbl_idx, bin_idx;
 
 	pte_efuse = ioremap(pte_efuse_phys, 4);
-	/* Select frequency tables. */
-	if (pte_efuse) {
-		pte_efuse_val = readl_relaxed(pte_efuse);
-		pvs = (pte_efuse_val >> 10) & 0x7;
-		iounmap(pte_efuse);
-		if (pvs == 0x7)
-			pvs = (pte_efuse_val >> 13) & 0x7;
-
-		switch (pvs) {
-		case 0x0:
-		case 0x7:
-			tbl_idx = PVS_SLOW;
-			break;
-		case 0x1:
-			tbl_idx = PVS_NOMINAL;
-			break;
-		case 0x3:
-			tbl_idx = PVS_FAST;
-			break;
-		case 0x4:
-			tbl_idx = PVS_FASTER;
-			break;
-		default:
-			tbl_idx = PVS_UNKNOWN;
-			break;
-		}
-	} else {
-		tbl_idx = PVS_UNKNOWN;
+	if (!pte_efuse) {
 		dev_err(drv.dev, "Unable to map QFPROM base\n");
-	}
-	if (tbl_idx == PVS_UNKNOWN) {
-		tbl_idx = PVS_SLOW;
-		dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
-			 pvs_names[tbl_idx]);
-	} else {
-		dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
+		return NULL;
 	}
 
-	return tbl_idx;
+	pte_efuse_val = readl_relaxed(pte_efuse);
+	iounmap(pte_efuse);
+
+	/* Select frequency tables. */
+	bin_idx = get_speed_bin(pte_efuse_val);
+	tbl_idx = get_pvs_bin(pte_efuse_val);
+
+	return &pvs_tables[bin_idx][tbl_idx];
 }
 
 static void __init drv_data_init(struct device *dev,
 				 const struct acpuclk_krait_params *params)
 {
-	int tbl_idx;
+	struct pvs_table *pvs;
 
 	drv.dev = dev;
 	drv.scalable = kmemdup(params->scalable, params->scalable_size,
@@ -1017,12 +1030,12 @@
 		GFP_KERNEL);
 	BUG_ON(!drv.bus_scale->usecase);
 
-	tbl_idx = select_freq_plan(params->pte_efuse_phys);
-	drv.acpu_freq_tbl = kmemdup(params->pvs_tables[tbl_idx].table,
-				    params->pvs_tables[tbl_idx].size,
-				    GFP_KERNEL);
+	pvs = select_freq_plan(params->pte_efuse_phys, params->pvs_tables);
+	BUG_ON(!pvs->table);
+
+	drv.acpu_freq_tbl = kmemdup(pvs->table, pvs->size, GFP_KERNEL);
 	BUG_ON(!drv.acpu_freq_tbl);
-	drv.boost_uv = params->pvs_tables[tbl_idx].boost_uv;
+	drv.boost_uv = pvs->boost_uv;
 
 	acpuclk_krait_data.power_collapse_khz = params->stby_khz;
 	acpuclk_krait_data.wait_for_irq_khz = params->stby_khz;
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index d615b85..3fa10e3 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -46,14 +46,18 @@
  */
 enum pvs {
 	PVS_SLOW = 0,
-	PVS_NOMINAL,
-	PVS_FAST,
-	PVS_FASTER,
-	PVS_UNKNOWN,
-	NUM_PVS
+	PVS_NOMINAL = 1,
+	PVS_FAST = 3,
+	PVS_FASTER = 4,
+	NUM_PVS = 7
 };
 
 /**
+ * The maximum number of speed bins.
+ */
+#define NUM_SPEED_BINS (16)
+
+/**
  * enum scalables - IDs of frequency scalable hardware blocks.
  */
 enum scalables {
@@ -111,14 +115,12 @@
  * @khz: Clock rate in KHz.
  * @src: Clock source ID.
  * @pri_src_sel: Input to select on the primary MUX.
- * @sec_src_sel: Input to select on the secondary MUX.
  * @pll_l_val: HFPLL "L" value to be applied when an HFPLL source is selected.
  */
 struct core_speed {
 	unsigned long khz;
 	int src;
 	u32 pri_src_sel;
-	u32 sec_src_sel;
 	u32 pll_l_val;
 };
 
@@ -188,8 +190,8 @@
 	const bool has_droop_ctl;
 	const u32 droop_offset;
 	const u32 droop_val;
-	const u32 low_vdd_l_max;
-	const u32 nom_vdd_l_max;
+	u32 low_vdd_l_max;
+	u32 nom_vdd_l_max;
 	const u32 low_vco_l_max;
 	const int vdd[NUM_HFPLL_VDD];
 };
@@ -200,6 +202,7 @@
  * @hfpll_base: Virtual base address of HFPLL registers.
  * @aux_clk_sel_phys: Physical address of auxiliary MUX.
  * @aux_clk_sel: Auxiliary mux input to select at boot.
+ * @sec_clk_sel: Secondary mux input to select at boot.
  * @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
  * @cur_speed: Pointer to currently-set speed.
  * @l2_vote: L2 performance level vote associate with the current CPU speed.
@@ -212,6 +215,7 @@
 	void __iomem *hfpll_base;
 	const phys_addr_t aux_clk_sel_phys;
 	const u32 aux_clk_sel;
+	const u32 sec_clk_sel;
 	const u32 l2cpmr_iaddr;
 	const struct core_speed *cur_speed;
 	unsigned int l2_vote;
@@ -237,7 +241,7 @@
  * @scalable: Array of scalables.
  * @scalable_size: Size of @scalable.
  * @hfpll_data: HFPLL configuration data.
- * @pvs_tables: CPU frequency tables.
+ * @pvs_tables: 2D array of CPU frequency tables.
  * @l2_freq_tbl: L2 frequency table.
  * @l2_freq_tbl_size: Size of @l2_freq_tbl.
  * @pte_efuse_phys: Physical address of PTE EFUSE.
@@ -248,7 +252,7 @@
 	struct scalable *scalable;
 	size_t scalable_size;
 	struct hfpll_data *hfpll_data;
-	struct pvs_table *pvs_tables;
+	struct pvs_table (*pvs_tables)[NUM_PVS];
 	struct l2_level *l2_freq_tbl;
 	size_t l2_freq_tbl_size;
 	phys_addr_t pte_efuse_phys;
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
index 050a24b..fa7d9d4 100644
--- a/arch/arm/mach-msm/adsp-8974.c
+++ b/arch/arm/mach-msm/adsp-8974.c
@@ -119,12 +119,17 @@
 	wmb();
 }
 
+static void restart_adsp(void)
+{
+	adsp_log_failure_reason();
+	subsystem_restart("adsp");
+}
+
 static void adsp_fatal_fn(struct work_struct *work)
 {
 	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
 		__func__);
-	adsp_log_failure_reason();
-	panic(MODULE_NAME ": Resetting the SoC");
+	restart_adsp();
 }
 
 static void adsp_smsm_state_cb(void *data, uint32_t old_state,
@@ -137,8 +142,7 @@
 	if (new_state & SMSM_RESET) {
 		pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
 			 __func__, new_state, old_state);
-		adsp_log_failure_reason();
-		panic(MODULE_NAME ": Resetting the SoC");
+		restart_adsp();
 	}
 }
 
@@ -156,7 +160,7 @@
 	/* The write needs to go through before the q6 is shutdown. */
 	mb();
 
-	pil_force_shutdown("q6");
+	pil_force_shutdown("adsp");
 	disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
 
 	return 0;
@@ -171,7 +175,7 @@
 		msleep(10000);
 	}
 
-	ret = pil_force_boot("q6");
+	ret = pil_force_boot("adsp");
 	enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
 	return ret;
 }
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index d5e4638..7ba22f4 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -171,7 +171,6 @@
 
 #define A2_NUM_PIPES		6
 #define A2_SUMMING_THRESHOLD	4096
-#define A2_DEFAULT_DESCRIPTORS	32
 #define A2_PHYS_BASE		0x124C2000
 #define A2_PHYS_SIZE		0x2000
 #define BUFFER_SIZE		2048
@@ -223,6 +222,7 @@
 static void rx_timer_work_func(struct work_struct *work);
 
 static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
+static struct delayed_work queue_rx_work;
 
 static struct workqueue_struct *bam_mux_rx_workqueue;
 static struct workqueue_struct *bam_mux_tx_workqueue;
@@ -430,21 +430,27 @@
 	rx_len_cached = bam_rx_pool_len;
 	mutex_unlock(&bam_rx_pool_mutexlock);
 
-	while (rx_len_cached < NUM_BUFFERS) {
+	while (bam_connection_is_active && rx_len_cached < NUM_BUFFERS) {
 		if (in_global_reset)
 			goto fail;
 
-		info = kmalloc(sizeof(struct rx_pkt_info), GFP_KERNEL);
+		info = kmalloc(sizeof(struct rx_pkt_info),
+						GFP_NOWAIT | __GFP_NOWARN);
 		if (!info) {
-			pr_err("%s: unable to alloc rx_pkt_info\n", __func__);
+			DMUX_LOG_KERR(
+			"%s: unable to alloc rx_pkt_info, will retry later\n",
+								__func__);
 			goto fail;
 		}
 
 		INIT_WORK(&info->work, handle_bam_mux_cmd);
 
-		info->skb = __dev_alloc_skb(BUFFER_SIZE, GFP_KERNEL);
+		info->skb = __dev_alloc_skb(BUFFER_SIZE,
+						GFP_NOWAIT | __GFP_NOWARN);
 		if (info->skb == NULL) {
-			DMUX_LOG_KERR("%s: unable to alloc skb\n", __func__);
+			DMUX_LOG_KERR(
+				"%s: unable to alloc skb, will retry later\n",
+								__func__);
 			goto fail_info;
 		}
 		ptr = skb_put(info->skb, BUFFER_SIZE);
@@ -488,11 +494,16 @@
 
 fail:
 	if (rx_len_cached == 0) {
-		DMUX_LOG_KERR("%s: RX queue failure\n", __func__);
-		in_global_reset = 1;
+		DMUX_LOG_KERR("%s: rescheduling\n", __func__);
+		schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
 	}
 }
 
+static void queue_rx_work_func(struct work_struct *work)
+{
+	queue_rx();
+}
+
 static void bam_mux_process_data(struct sk_buff *rx_skb)
 {
 	unsigned long flags;
@@ -2422,6 +2433,7 @@
 	init_completion(&bam_connection_completion);
 	init_completion(&dfab_unvote_completion);
 	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+	INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
 	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
 
 	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
diff --git a/arch/arm/mach-msm/batterydata-lib.c b/arch/arm/mach-msm/batterydata-lib.c
new file mode 100644
index 0000000..2be591c
--- /dev/null
+++ b/arch/arm/mach-msm/batterydata-lib.c
@@ -0,0 +1,338 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
+
+int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+int is_between(int left, int right, int value)
+{
+	if (left >= right && left >= value && value >= right)
+		return 1;
+	if (left <= right && left <= value && value <= right)
+		return 1;
+	return 0;
+}
+
+static int interpolate_single_lut(struct single_row_lut *lut, int x)
+{
+	int i, result;
+
+	if (x < lut->x[0]) {
+		pr_debug("x %d less than known range return y = %d lut = %pS\n",
+							x, lut->y[0], lut);
+		return lut->y[0];
+	}
+	if (x > lut->x[lut->cols - 1]) {
+		pr_debug("x %d more than known range return y = %d lut = %pS\n",
+						x, lut->y[lut->cols - 1], lut);
+		return lut->y[lut->cols - 1];
+	}
+
+	for (i = 0; i < lut->cols; i++)
+		if (x <= lut->x[i])
+			break;
+	if (x == lut->x[i]) {
+		result = lut->y[i];
+	} else {
+		result = linear_interpolate(
+			lut->y[i - 1],
+			lut->x[i - 1],
+			lut->y[i],
+			lut->x[i],
+			x);
+	}
+	return result;
+}
+
+int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp)
+{
+	/* batt_temp is in tenths of degC - convert it to degC for lookups */
+	batt_temp = batt_temp/10;
+	return interpolate_single_lut(fcc_temp_lut, batt_temp);
+}
+
+int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
+		int cycles)
+{
+	/*
+	 * sf table could be null when no battery aging data is available, in
+	 * that case return 100%
+	 */
+	if (fcc_sf_lut)
+		return interpolate_single_lut(fcc_sf_lut, cycles);
+	else
+		return 100;
+}
+
+int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc)
+{
+	int i, scalefactorrow1, scalefactorrow2, scalefactor, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	/*
+	 * sf table could be null when no battery aging data is available, in
+	 * that case return 100%
+	 */
+	if (!sf_lut)
+		return 100;
+
+	rows = sf_lut->rows;
+	cols = sf_lut->cols;
+	if (pc > sf_lut->percent[0]) {
+		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+		row1 = 0;
+		row2 = 0;
+	}
+	if (pc < sf_lut->percent[rows - 1]) {
+		pr_debug("pc %d less than known pc ranges for sf\n", pc);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	}
+	for (i = 0; i < rows; i++) {
+		if (pc == sf_lut->percent[i]) {
+			row1 = i;
+			row2 = i;
+			break;
+		}
+		if (pc > sf_lut->percent[i]) {
+			row1 = i - 1;
+			row2 = i;
+			break;
+		}
+	}
+
+	if (row_entry < sf_lut->row_entries[0])
+		row_entry = sf_lut->row_entries[0];
+	if (row_entry > sf_lut->row_entries[cols - 1])
+		row_entry = sf_lut->row_entries[cols - 1];
+
+	for (i = 0; i < cols; i++)
+		if (row_entry <= sf_lut->row_entries[i])
+			break;
+	if (row_entry == sf_lut->row_entries[i]) {
+		scalefactor = linear_interpolate(
+				sf_lut->sf[row1][i],
+				sf_lut->percent[row1],
+				sf_lut->sf[row2][i],
+				sf_lut->percent[row2],
+				pc);
+		return scalefactor;
+	}
+
+	scalefactorrow1 = linear_interpolate(
+				sf_lut->sf[row1][i - 1],
+				sf_lut->row_entries[i - 1],
+				sf_lut->sf[row1][i],
+				sf_lut->row_entries[i],
+				row_entry);
+
+	scalefactorrow2 = linear_interpolate(
+				sf_lut->sf[row2][i - 1],
+				sf_lut->row_entries[i - 1],
+				sf_lut->sf[row2][i],
+				sf_lut->row_entries[i],
+				row_entry);
+
+	scalefactor = linear_interpolate(
+				scalefactorrow1,
+				sf_lut->percent[row1],
+				scalefactorrow2,
+				sf_lut->percent[row2],
+				pc);
+
+	return scalefactor;
+}
+
+/* get ocv given a soc  -- reverse lookup */
+int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int pc)
+{
+	int i, ocvrow1, ocvrow2, ocv, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	rows = pc_temp_ocv->rows;
+	cols = pc_temp_ocv->cols;
+	if (pc > pc_temp_ocv->percent[0]) {
+		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+		row1 = 0;
+		row2 = 0;
+	}
+	if (pc < pc_temp_ocv->percent[rows - 1]) {
+		pr_debug("pc %d less than known pc ranges for sf\n", pc);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	}
+	for (i = 0; i < rows; i++) {
+		if (pc == pc_temp_ocv->percent[i]) {
+			row1 = i;
+			row2 = i;
+			break;
+		}
+		if (pc > pc_temp_ocv->percent[i]) {
+			row1 = i - 1;
+			row2 = i;
+			break;
+		}
+	}
+
+	if (batt_temp_degc < pc_temp_ocv->temp[0])
+		batt_temp_degc = pc_temp_ocv->temp[0];
+	if (batt_temp_degc > pc_temp_ocv->temp[cols - 1])
+		batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+
+	for (i = 0; i < cols; i++)
+		if (batt_temp_degc <= pc_temp_ocv->temp[i])
+			break;
+	if (batt_temp_degc == pc_temp_ocv->temp[i]) {
+		ocv = linear_interpolate(
+				pc_temp_ocv->ocv[row1][i],
+				pc_temp_ocv->percent[row1],
+				pc_temp_ocv->ocv[row2][i],
+				pc_temp_ocv->percent[row2],
+				pc);
+		return ocv;
+	}
+
+	ocvrow1 = linear_interpolate(
+				pc_temp_ocv->ocv[row1][i - 1],
+				pc_temp_ocv->temp[i - 1],
+				pc_temp_ocv->ocv[row1][i],
+				pc_temp_ocv->temp[i],
+				batt_temp_degc);
+
+	ocvrow2 = linear_interpolate(
+				pc_temp_ocv->ocv[row2][i - 1],
+				pc_temp_ocv->temp[i - 1],
+				pc_temp_ocv->ocv[row2][i],
+				pc_temp_ocv->temp[i],
+				batt_temp_degc);
+
+	ocv = linear_interpolate(
+				ocvrow1,
+				pc_temp_ocv->percent[row1],
+				ocvrow2,
+				pc_temp_ocv->percent[row2],
+				pc);
+
+	return ocv;
+}
+
+int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int ocv)
+{
+	int i, j, pcj, pcj_minus_one, pc;
+	int rows = pc_temp_ocv->rows;
+	int cols = pc_temp_ocv->cols;
+
+	if (batt_temp_degc < pc_temp_ocv->temp[0]) {
+		pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
+		batt_temp_degc = pc_temp_ocv->temp[0];
+	}
+
+	if (batt_temp_degc > pc_temp_ocv->temp[cols - 1]) {
+		pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
+		batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+	}
+
+	for (j = 0; j < cols; j++)
+		if (batt_temp_degc <= pc_temp_ocv->temp[j])
+			break;
+	if (batt_temp_degc == pc_temp_ocv->temp[j]) {
+		/* found an exact match for temp in the table */
+		if (ocv >= pc_temp_ocv->ocv[0][j])
+			return pc_temp_ocv->percent[0];
+		if (ocv <= pc_temp_ocv->ocv[rows - 1][j])
+			return pc_temp_ocv->percent[rows - 1];
+		for (i = 0; i < rows; i++) {
+			if (ocv >= pc_temp_ocv->ocv[i][j]) {
+				if (ocv == pc_temp_ocv->ocv[i][j])
+					return pc_temp_ocv->percent[i];
+				pc = linear_interpolate(
+					pc_temp_ocv->percent[i],
+					pc_temp_ocv->ocv[i][j],
+					pc_temp_ocv->percent[i - 1],
+					pc_temp_ocv->ocv[i - 1][j],
+					ocv);
+				return pc;
+			}
+		}
+	}
+
+	/*
+	 * batt_temp_degc is within temperature for
+	 * column j-1 and j
+	 */
+	if (ocv >= pc_temp_ocv->ocv[0][j])
+		return pc_temp_ocv->percent[0];
+	if (ocv <= pc_temp_ocv->ocv[rows - 1][j - 1])
+		return pc_temp_ocv->percent[rows - 1];
+
+	pcj_minus_one = 0;
+	pcj = 0;
+	for (i = 0; i < rows-1; i++) {
+		if (pcj == 0
+			&& is_between(pc_temp_ocv->ocv[i][j],
+				pc_temp_ocv->ocv[i+1][j], ocv)) {
+			pcj = linear_interpolate(
+				pc_temp_ocv->percent[i],
+				pc_temp_ocv->ocv[i][j],
+				pc_temp_ocv->percent[i + 1],
+				pc_temp_ocv->ocv[i+1][j],
+				ocv);
+		}
+
+		if (pcj_minus_one == 0
+			&& is_between(pc_temp_ocv->ocv[i][j-1],
+				pc_temp_ocv->ocv[i+1][j-1], ocv)) {
+			pcj_minus_one = linear_interpolate(
+				pc_temp_ocv->percent[i],
+				pc_temp_ocv->ocv[i][j-1],
+				pc_temp_ocv->percent[i + 1],
+				pc_temp_ocv->ocv[i+1][j-1],
+				ocv);
+		}
+
+		if (pcj && pcj_minus_one) {
+			pc = linear_interpolate(
+				pcj_minus_one,
+				pc_temp_ocv->temp[j-1],
+				pcj,
+				pc_temp_ocv->temp[j],
+				batt_temp_degc);
+			return pc;
+		}
+	}
+
+	if (pcj)
+		return pcj;
+
+	if (pcj_minus_one)
+		return pcj_minus_one;
+
+	pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%\n",
+							ocv, batt_temp_degc);
+	return 100;
+}
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index f362a72..d9fa061 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 static struct single_row_lut desay_5200_fcc_temp = {
 	.x		= {-20, 0, 25, 40},
@@ -76,7 +76,7 @@
 	},
 };
 
-struct pm8921_bms_battery_data desay_5200_data = {
+struct bms_battery_data desay_5200_data = {
 	.fcc			= 5200,
 	.fcc_temp_lut		= &desay_5200_fcc_temp,
 	.fcc_sf_lut		= &desay_5200_fcc_sf,
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 81ab121..fb4f967 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 static struct single_row_lut fcc_temp = {
 	.x		= {-20, 0, 25, 40, 65},
@@ -99,7 +99,7 @@
 	}
 };
 
-struct pm8921_bms_battery_data palladium_1500_data = {
+struct bms_battery_data palladium_1500_data = {
 	.fcc			= 1500,
 	.fcc_temp_lut		= &fcc_temp,
 	.pc_temp_ocv_lut	= &pc_temp_ocv,
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index a08f45c..cb03d4b 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -31,6 +31,7 @@
 	.drv = GPIOMUX_DRV_8MA,
 	.func = GPIOMUX_FUNC_GPIO,
 };
+#endif
 
 /* The SPI configurations apply to GSBI 5*/
 static struct gpiomux_setting gpio_spi_config = {
@@ -60,6 +61,7 @@
 	.pull = GPIOMUX_PULL_UP,
 };
 
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 struct msm_gpiomux_config apq8064_ethernet_configs[] = {
 	{
 		.gpio = 43,
@@ -361,6 +363,22 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting audio_auxpcm[] = {
+/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_GPIO,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+/* Active state */
+	{
+		.func = GPIOMUX_FUNC_1,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+};
+
+
 static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv  = GPIOMUX_DRV_2MA,
@@ -682,7 +700,6 @@
 			[GPIOMUX_SUSPENDED] = &gsbi1_uart_config,
 		},
 	},
-#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 	{
 		.gpio      = 51,		/* GSBI5 QUP SPI_DATA_MOSI */
 		.settings = {
@@ -713,7 +730,6 @@
 			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
 		},
 	},
-#endif
 	{
 		.gpio      = 30,		/* FP CS */
 		.settings = {
@@ -846,6 +862,37 @@
 	},
 };
 
+static struct msm_gpiomux_config mpq8064_audio_auxpcm_configs[] __initdata = {
+	{
+		.gpio = 43,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 44,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 45,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 46,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+};
+
 /* External 3.3 V regulator enable */
 static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
 	{
@@ -1527,6 +1574,10 @@
 
 	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 		machine_is_mpq8064_dtv()) {
+
+		msm_gpiomux_install(mpq8064_audio_auxpcm_configs,
+			ARRAY_SIZE(mpq8064_audio_auxpcm_configs));
+
 		msm_gpiomux_install(mpq8064_spkr_i2s_config,
 			ARRAY_SIZE(mpq8064_spkr_i2s_config));
 	}
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 122505e..3be7fc6 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,26 +24,49 @@
 
 #ifdef CONFIG_MSM_DCVS
 static struct msm_dcvs_freq_entry grp3d_freq[] = {
-	{0, 0, 333932},
-	{0, 0, 497532},
-	{0, 0, 707610},
-	{0, 0, 844545},
+	{0, 900, 0, 0, 0},
+	{0, 950, 0, 0, 0},
+	{0, 950, 0, 0, 0},
+	{0, 1200, 1, 100, 100},
 };
 
 static struct msm_dcvs_core_info grp3d_core_info = {
-	.freq_tbl = &grp3d_freq[0],
-	.core_param = {
-		.max_time_us = 100000,
-		.num_freq = ARRAY_SIZE(grp3d_freq),
+	.freq_tbl	= &grp3d_freq[0],
+	.core_param	= {
+		.core_type	= MSM_DCVS_CORE_TYPE_GPU,
 	},
-	.algo_param = {
-		.slack_time_us = 39000,
-		.disable_pc_threshold = 86000,
-		.ss_window_size = 1000000,
-		.ss_util_pct = 95,
-		.em_max_util_pct = 97,
-		.ss_iobusy_conv = 100,
+	.algo_param	= {
+		.disable_pc_threshold	= 0,
+		.em_win_size_min_us	= 100000,
+		.em_win_size_max_us	= 300000,
+		.em_max_util_pct	= 97,
+		.group_id		= 0,
+		.max_freq_chg_time_us	= 100000,
+		.slack_mode_dynamic	= 0,
+		.slack_time_min_us	= 39000,
+		.slack_time_max_us	= 39000,
+		.ss_win_size_min_us	= 1000000,
+		.ss_win_size_max_us	= 1000000,
+		.ss_util_pct		= 95,
+		.ss_iobusy_conv		= 100,
 	},
+
+
+	.energy_coeffs	= {
+		.leakage_coeff_a	= -17720,
+		.leakage_coeff_b	= 37,
+		.leakage_coeff_c	= 3329,
+		.leakage_coeff_d	= -277,
+
+		.active_coeff_a		= 2492,
+		.active_coeff_b		= 0,
+		.active_coeff_c		= 0
+	},
+
+	.power_param	= {
+		.current_temp	= 25,
+		.num_freq	= ARRAY_SIZE(grp3d_freq),
+	}
 };
 #endif /* CONFIG_MSM_DCVS */
 
@@ -251,11 +274,17 @@
 {
 	unsigned int version = socinfo_get_version();
 
-	if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
-		(SOCINFO_VERSION_MINOR(version) == 1))
-		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
-	else
-		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
+	if (cpu_is_apq8064ab())
+		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
+	if (SOCINFO_VERSION_MAJOR(version) == 2) {
+		kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 2);
+	} else {
+		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+				(SOCINFO_VERSION_MINOR(version) == 1))
+			kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
+		else
+			kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
+	}
 
 	platform_device_register(&device_kgsl_3d0);
 }
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 3b47d2e..f6423c8 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -115,7 +115,6 @@
 /* Initial PM8921 GPIO configurations */
 static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
 	PM8921_GPIO_OUTPUT(14, 1, HIGH),	/* HDMI Mux Selector */
-	PM8921_GPIO_OUTPUT(23, 0, HIGH),	/* touchscreen power FET */
 	PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
 	PM8921_GPIO_OUTPUT_FUNC(26, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
 	PM8921_GPIO_OUTPUT_VIN(30, 1, PM_GPIO_VIN_VPH), /* SMB349 susp line */
@@ -146,10 +145,13 @@
 	PM8921_GPIO_OUTPUT(37, 0, LOW),	/* MUX1_SEL */
 };
 
+static struct pm8xxx_gpio_init touchscreen_gpios[] __initdata = {
+	PM8921_GPIO_OUTPUT(23, 0, HIGH),	/* touchscreen power FET */
+};
+
 /* Initial PM8917 GPIO configurations */
 static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
 	PM8921_GPIO_OUTPUT(14, 1, HIGH),	/* HDMI Mux Selector */
-	PM8921_GPIO_OUTPUT(23, 0, HIGH),	/* touchscreen power FET */
 	PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
 	PM8921_GPIO_OUTPUT(26, 1, HIGH), /* Backlight: on */
 	PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
@@ -210,6 +212,8 @@
 		apq8064_configure_gpios(pm8917_gpios, ARRAY_SIZE(pm8917_gpios));
 
 	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid()) {
+		apq8064_configure_gpios(touchscreen_gpios,
+					ARRAY_SIZE(touchscreen_gpios));
 		if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
 			apq8064_configure_gpios(pm8921_cdp_kp_gpios,
 					ARRAY_SIZE(pm8921_cdp_kp_gpios));
@@ -395,6 +399,8 @@
 	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
+	.alarm_low_mv		= 3400,
+	.alarm_high_mv		= 4000,
 	.resume_voltage_delta	= 100,
 	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 6cdafbc..ef3c81d 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -771,4 +771,10 @@
 				= ARRAY_SIZE(vreg_consumers_8917_S1);
 		}
 	}
+
+	/*
+	 * Switch to 8960_PM8917 rpm-regulator version so that TCXO workaround
+	 * is applied to PM8917 regulators L25, L26, L27, and L28.
+	 */
+	apq8064_rpm_regulator_pdata.version = RPM_VREG_VERSION_8960_PM8917;
 }
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index c81a637..379d7ae 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -338,6 +338,11 @@
 		apq8064_add_sdcc(2, apq8064_sdc2_pdata);
 
 	if (apq8064_sdc3_pdata) {
+		if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+			apq8064_sdc3_pdata->uhs_caps &= ~(MMC_CAP_UHS_SDR12 |
+				MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_DDR50 |
+				MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104);
+		}
 		if (!machine_is_apq8064_cdp()) {
 			apq8064_sdc3_pdata->wpswitch_gpio = 0;
 			apq8064_sdc3_pdata->is_wpswitch_active_low = false;
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 07acac6..cc9dcbb 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -470,7 +470,8 @@
 		const struct ion_platform_heap *heap =
 			&(apq8064_ion_pdata.heaps[i]);
 
-		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+		if (heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP
+			&& heap->extra_data) {
 			struct ion_cp_heap_pdata *data = heap->extra_data;
 
 			reusable_count += (data->reusable) ? 1 : 0;
@@ -492,7 +493,7 @@
 			int fixed_position = NOT_FIXED;
 			int mem_is_fmem = 0;
 
-			switch (heap->type) {
+			switch ((int)heap->type) {
 			case ION_HEAP_TYPE_CP:
 				mem_is_fmem = ((struct ion_cp_heap_pdata *)
 					heap->extra_data)->mem_is_fmem;
@@ -553,7 +554,7 @@
 			int fixed_position = NOT_FIXED;
 			struct ion_cp_heap_pdata *pdata = NULL;
 
-			switch (heap->type) {
+			switch ((int) heap->type) {
 			case ION_HEAP_TYPE_CP:
 				pdata =
 				(struct ion_cp_heap_pdata *)heap->extra_data;
@@ -926,7 +927,8 @@
 static void __init apq8064_ehci_host_init(void)
 {
 	if (machine_is_apq8064_liquid() || machine_is_mpq8064_cdp() ||
-		machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+		machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv() ||
+					machine_is_apq8064_cdp()) {
 		if (machine_is_apq8064_liquid())
 			msm_ehci_host_pdata3.dock_connect_irq =
 					PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
@@ -1768,6 +1770,27 @@
 	},
 };
 
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 70000000UL,
+		.ib = 70000000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 2480000000UL,
+		.ib = 2480000000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = (64 * 8) * 1000000UL,
+		.ab = (64 * 8) *  100000UL,
+	},
+};
+
 static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1781,6 +1804,10 @@
 		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
 		qseecom_enable_sfpb_vectors,
 	},
+	{
+		ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+		qseecom_enable_dfab_sfpb_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata qseecom_bus_pdata = {
@@ -1930,6 +1957,7 @@
 	.ramdump_delay_ms = 2000,
 	.early_power_on = 1,
 	.sfr_query = 1,
+	.send_shdn = 1,
 	.vddmin_resource = &mdm_vddmin_rscs,
 	.peripheral_platform_device = &apq8064_device_hsic_host,
 	.ramdump_timeout_ms = 120000,
@@ -2440,7 +2468,6 @@
 	&apq8064_device_ext_3p3v_vreg,
 	&apq8064_device_ssbi_pmic1,
 	&apq8064_device_ssbi_pmic2,
-	&apq8064_device_ext_ts_sw_vreg,
 };
 
 static struct platform_device *pm8917_common_devices[] __initdata = {
@@ -2448,7 +2475,6 @@
 	&apq8064_device_ext_3p3v_vreg,
 	&apq8064_device_ssbi_pmic1,
 	&apq8064_device_ssbi_pmic2,
-	&apq8064_device_ext_ts_sw_vreg,
 };
 
 static struct platform_device *common_devices[] __initdata = {
@@ -2543,6 +2569,7 @@
 	&msm_gss,
 	&apq8064_rtb_device,
 	&apq8064_cpu_idle_device,
+	&apq8064_msm_gov_device,
 	&apq8064_device_cache_erp,
 	&msm8960_device_ebi1_ch0_erp,
 	&msm8960_device_ebi1_ch1_erp,
@@ -2566,6 +2593,7 @@
 #ifdef CONFIG_BATTERY_BCL
 	&battery_bcl_device,
 #endif
+	&apq8064_msm_mpd_device,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -2575,6 +2603,7 @@
 #ifdef CONFIG_MSM_ROTATOR
 	&msm_rotator_device,
 #endif
+	&msm8064_pc_cntr,
 };
 
 static struct platform_device
@@ -3344,6 +3373,8 @@
 	else
 		platform_add_devices(pm8917_common_devices,
 					ARRAY_SIZE(pm8917_common_devices));
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		platform_device_register(&apq8064_device_ext_ts_sw_vreg);
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 			machine_is_mpq8064_dtv()))
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 59e4ba1..402aec4 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -320,6 +320,8 @@
 	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
+	.alarm_low_mv		= 3400,
+	.alarm_high_mv		= 4000,
 	.resume_voltage_delta	= 100,
 	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index ab35948..a6a90a7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -518,7 +518,8 @@
 		const struct ion_platform_heap *heap =
 						&(msm8930_ion_pdata.heaps[i]);
 
-		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+		if (heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP
+			&& heap->extra_data) {
 			struct ion_cp_heap_pdata *data = heap->extra_data;
 
 			reusable_count += (data->reusable) ? 1 : 0;
@@ -540,7 +541,7 @@
 			int fixed_position = NOT_FIXED;
 			int mem_is_fmem = 0;
 
-			switch (heap->type) {
+			switch ((int) heap->type) {
 			case ION_HEAP_TYPE_CP:
 				mem_is_fmem = ((struct ion_cp_heap_pdata *)
 					heap->extra_data)->mem_is_fmem;
@@ -601,7 +602,7 @@
 			int fixed_position = NOT_FIXED;
 			struct ion_cp_heap_pdata *pdata = NULL;
 
-			switch (heap->type) {
+			switch ((int) heap->type) {
 			case ION_HEAP_TYPE_CP:
 				pdata =
 				(struct ion_cp_heap_pdata *)heap->extra_data;
@@ -1047,6 +1048,27 @@
 	},
 };
 
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = (64 * 8) * 1000000UL,
+		.ab = (64 * 8) *  100000UL,
+	},
+};
+
 static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1060,6 +1082,10 @@
 		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
 		qseecom_enable_sfpb_vectors,
 	},
+	{
+		ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+		qseecom_enable_dfab_sfpb_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata qseecom_bus_pdata = {
@@ -2388,7 +2414,6 @@
 #endif
 	&msm8930_rtb_device,
 	&msm8930_cpu_idle_device,
-	&msm8930_msm_gov_device,
 	&msm_bus_8930_apps_fabric,
 	&msm_bus_8930_sys_fabric,
 	&msm_bus_8930_mm_fabric,
@@ -2398,6 +2423,7 @@
 	&msm8930_iommu_domain_device,
 	&msm_tsens_device,
 	&msm8930_cache_dump_device,
+	&msm8930_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index ae74285..f6c3653 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -401,6 +401,8 @@
 	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
+	.alarm_low_mv		= 3400,
+	.alarm_high_mv		= 4000,
 	.resume_voltage_delta	= 100,
 	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 8ed9666..7115e40 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -562,7 +562,8 @@
 		const struct ion_platform_heap *heap =
 						&(msm8960_ion_pdata.heaps[i]);
 
-		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+		if (heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP
+			&& heap->extra_data) {
 			struct ion_cp_heap_pdata *data = heap->extra_data;
 
 			reusable_count += (data->reusable) ? 1 : 0;
@@ -587,7 +588,7 @@
 			int fixed_position = NOT_FIXED;
 			int mem_is_fmem = 0;
 
-			switch (heap->type) {
+			switch ((int) heap->type) {
 			case ION_HEAP_TYPE_CP:
 				mem_is_fmem = ((struct ion_cp_heap_pdata *)
 					heap->extra_data)->mem_is_fmem;
@@ -666,7 +667,7 @@
 			int fixed_position = NOT_FIXED;
 			struct ion_cp_heap_pdata *pdata = NULL;
 
-			switch (heap->type) {
+			switch ((int) heap->type) {
 			case ION_HEAP_TYPE_CP:
 				pdata =
 				(struct ion_cp_heap_pdata *)heap->extra_data;
@@ -1112,6 +1113,27 @@
 	},
 };
 
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) * 100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = (64 * 8) * 1000000UL,
+		.ab = (64 * 8) *  100000UL,
+	},
+};
+
 static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1125,6 +1147,10 @@
 		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
 		qseecom_enable_sfpb_vectors,
 	},
+	{
+		ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+		qseecom_enable_dfab_sfpb_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata qseecom_bus_pdata = {
@@ -2737,13 +2763,13 @@
 	&msm8960_device_watchdog,
 	&msm8960_rtb_device,
 	&msm8960_cpu_idle_device,
-	&msm8960_msm_gov_device,
 	&msm8960_device_cache_erp,
 	&msm8960_device_ebi1_ch0_erp,
 	&msm8960_device_ebi1_ch1_erp,
 	&msm8960_cache_dump_device,
 	&msm8960_iommu_domain_device,
 	&msm_tsens_device,
+	&msm8960_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -3158,13 +3184,22 @@
 #endif
 }
 
+static void __init msm8960_tsens_init(void)
+{
+	if (cpu_is_msm8960())
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
+			return;
+
+	msm_tsens_early_init(&msm_tsens_pdata);
+}
+
 static void __init msm8960_cdp_init(void)
 {
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
 	platform_device_register(&msm_gpio_device);
-	msm_tsens_early_init(&msm_tsens_pdata);
+	msm8960_tsens_init();
 	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 479dec6..8568340 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -271,6 +271,30 @@
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
 	},
+	{
+		.gpio      = 53,		/* BLSP2 QUP4 SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 54,		/* BLSP2 QUP4 SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 56,		/* BLSP2 QUP4 SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 55,		/* BLSP2 QUP4 SPI_CS0_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm8974_slimbus_config[] __initdata = {
@@ -290,22 +314,34 @@
 
 static struct gpiomux_setting cam_settings[] = {
 	{
-		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.func = GPIOMUX_FUNC_1, /*active 1*/ /* 0 */
 		.drv = GPIOMUX_DRV_2MA,
 		.pull = GPIOMUX_PULL_NONE,
 	},
 
 	{
-		.func = GPIOMUX_FUNC_1, /*suspend*/
+		.func = GPIOMUX_FUNC_1, /*suspend*/ /* 1 */
 		.drv = GPIOMUX_DRV_2MA,
 		.pull = GPIOMUX_PULL_DOWN,
 	},
 
 	{
-		.func = GPIOMUX_FUNC_1, /*i2c suspend*/
+		.func = GPIOMUX_FUNC_1, /*i2c suspend*/ /* 2 */
 		.drv = GPIOMUX_DRV_2MA,
 		.pull = GPIOMUX_PULL_KEEPER,
 	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 0*/ /* 3 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend 0*/ /* 4 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
 };
 
 static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
@@ -333,8 +369,8 @@
 	{
 		.gpio = 18, /* WEBCAM1_RESET_N / CAM_MCLK3 */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
-			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[4],
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 2919f06..fe7670b 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -18,8 +18,8 @@
 #include <mach/gpiomux.h>
 
 static struct gpiomux_setting gpio_uart_config = {
-	.func = GPIOMUX_FUNC_2,
-	.drv = GPIOMUX_DRV_16MA,
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 	.dir = GPIOMUX_OUT_HIGH,
 };
@@ -38,13 +38,13 @@
 
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
-		.gpio      = 45,	       /* BLSP1 UART TX */
+		.gpio      = 8,	       /* BLSP1 UART TX */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
 	},
 	{
-		.gpio      = 46,	       /* BLSP1 UART RX */
+		.gpio      = 9,	       /* BLSP1 UART RX */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 99b9f16..37e93b6 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -30,8 +30,40 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/clk-provider.h>
+#include <mach/qpnp-int.h>
+#include <mach/msm_memtypes.h>
 #include "clock.h"
 
+#define MSM_KERNEL_EBI_SIZE	0x51000
+
+static struct memtype_reserve msm9625_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static int msm9625_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static void __init msm9625_calculate_reserve_sizes(void)
+{
+	msm9625_reserve_table[MEMTYPE_EBI1].size += MSM_KERNEL_EBI_SIZE;
+}
+
+static struct reserve_info msm9625_reserve_info __initdata = {
+	.memtype_reserve_table = msm9625_reserve_table,
+	.calculate_reserve_sizes = msm9625_calculate_reserve_sizes,
+	.paddr_to_memtype = msm9625_paddr_to_memtype,
+};
+
+
 #define L2CC_AUX_CTRL	((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
 			(0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
 			(0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT))
@@ -62,6 +94,7 @@
 static struct of_device_id irq_match[] __initdata  = {
 	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
 	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{ .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
 	{}
 };
 
@@ -75,6 +108,8 @@
 			"msm_serial_hsl.0", NULL),
 	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
 			"spi_qsd.1", NULL),
+	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
+			"spmi-pmic-arb.0", NULL),
 	{}
 };
 
@@ -93,6 +128,13 @@
 	.init = msm_dt_timer_init
 };
 
+static void __init msm9625_reserve(void)
+{
+	reserve_info = &msm9625_reserve_info;
+	msm_reserve();
+}
+
+
 void __init msm9625_init(void)
 {
 	if (socinfo_init() < 0)
@@ -111,5 +153,5 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
 	.dt_compat = msm9625_dt_match,
-	.nr_irqs = -1,
+	.reserve = msm9625_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index b4f6968..1d6eb01 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -941,6 +941,8 @@
 
 static void __init fsm9xxx_init(void)
 {
+	msm_clock_init(&fsm9xxx_clock_init_data);
+
 	regulator_has_full_constraints();
 
 #if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
@@ -977,7 +979,6 @@
 {
 	msm_shared_ram_phys = 0x00100000;
 	msm_map_fsm9xxx_io();
-	msm_clock_init(&fsm9xxx_clock_init_data);
 	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed!\n",
 		       __func__);
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 47e8381..6e3d10a 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -266,16 +266,16 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	20, 0, 0, 0, 0, 0, 0, 0,
+	20, 1, 0, 25, 9, 12, 0, 0,
 	/* T7 Object */
 	24, 12, 10,
 	/* T8 Object */
-	30, 0, 20, 20, 0, 0, 9, 45, 10, 192,
+	30, 0, 20, 20, 0, 0, 0, 0, 10, 192,
 	/* T9 Object */
-	3, 0, 0, 18, 11, 0, 16, 60, 3, 1,
-	0, 1, 1, 0, 10, 10, 10, 10, 107, 3,
-	223, 1, 0, 0, 0, 0, 0, 0, 0, 0,
-	20, 15, 0, 0, 2,
+	131, 0, 0, 18, 11, 0, 16, 70, 2, 1,
+	0, 2, 1, 62, 10, 10, 10, 10, 107, 3,
+	223, 1, 2, 2, 20, 20, 172, 40, 139, 110,
+	10, 15, 0, 0, 0,
 	/* T15 Object */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0,
@@ -291,7 +291,7 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T40 Object */
-	17, 0, 0, 30, 30,
+	0, 0, 0, 0, 0,
 	/* T42 Object */
 	3, 20, 45, 40, 128, 0, 0, 0,
 	/* T46 Object */
@@ -299,12 +299,12 @@
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* T48 Object */
-	1, 128, 96, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 6, 6, 0, 0, 63, 4, 64,
-	10, 0, 32, 5, 0, 38, 0, 8, 0, 0,
+	1, 12, 64, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
+	10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
 	0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0,
+	10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
+	80, 100, 15, 3,
 };
 
 static struct mxt_config_info mxt_config_array[] = {
@@ -822,6 +822,7 @@
 			mxt_config_array[0].config_length =
 					ARRAY_SIZE(mxt_config_data_evt);
 			mxt_platform_data.panel_maxy = 875;
+			mxt_platform_data.need_calibration = true;
 			mxt_vkey_setup();
 		}
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 2a51e66..13c4be2 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -841,7 +841,7 @@
 static void __init msm8625_reserve(void)
 {
 	msm7x27a_reserve();
-	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	memblock_remove(MSM8625_CPU_PHYS, SZ_8);
 	memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
 }
 
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 205db58..ee13e04 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -5190,7 +5190,7 @@
 
 	int bahama_not_marimba = bahama_present();
 
-	if (bahama_not_marimba == -1) {
+	if (bahama_not_marimba < 0) {
 		printk(KERN_WARNING "%s: bahama_present: %d\n",
 				__func__, bahama_not_marimba);
 		return -ENODEV;
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index a889d39..d831ad2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5478,7 +5478,8 @@
 	for (i = 0; i < ion_pdata.nr; i++) {
 		struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
 
-		if (heap->extra_data && heap->type == ION_HEAP_TYPE_CP) {
+		if (heap->extra_data &&
+			heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP) {
 			int map_all = ((struct ion_cp_heap_pdata *)
 				heap->extra_data)->iommu_map_all;
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f6b0c4f..ec8e438 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -276,6 +276,7 @@
 
 static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
 	.is_phy_status_timer_on = 1,
+	.prop_chg = 0,
 };
 
 #ifdef CONFIG_SERIAL_MSM_HS
@@ -811,7 +812,7 @@
 
 static void __init msm8625_reserve(void)
 {
-	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	memblock_remove(MSM8625_CPU_PHYS, SZ_8);
 	msm7627a_reserve();
 }
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 9ff039f0..2cd2cd4 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1534,6 +1534,11 @@
 static CLK_SDC(sdc4_clk, 4, 3,  33000000,  67000000);
 static CLK_SDC(sdc5_clk, 5, 2,  33000000,  67000000);
 
+static unsigned long fmax_sdc1_8064v2[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 100000000,
+	[VDD_DIG_NOMINAL] = 200000000,
+};
+
 #define F_TSIF_REF(f, s, d, m, n) \
 	{ \
 		.freq_hz = f, \
@@ -1907,6 +1912,7 @@
 	F_CE3(        0, gnd,   1),
 	F_CE3( 48000000, pll8,  8),
 	F_CE3(100000000, pll3, 12),
+	F_CE3(120000000, pll3, 10),
 	F_END
 };
 
@@ -1929,6 +1935,11 @@
 	},
 };
 
+static unsigned long fmax_ce3_8064v2[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     =  57000000,
+	[VDD_DIG_NOMINAL] = 120000000,
+};
+
 static struct branch_clk ce3_core_clk = {
 	.b = {
 		.ctl_reg = CE3_CORE_CLK_CTL_REG,
@@ -3540,11 +3551,12 @@
 	F_GFX3D(145455000, pll2,  2, 11),
 	F_GFX3D(160000000, pll2,  1,  5),
 	F_GFX3D(177778000, pll2,  2,  9),
+	F_GFX3D(192000000, pll8,  1,  2),
 	F_GFX3D(200000000, pll2,  1,  4),
 	F_GFX3D(228571000, pll2,  2,  7),
 	F_GFX3D(266667000, pll2,  1,  3),
-	F_GFX3D(325000000, pll15, 1,  3),
 	F_GFX3D(400000000, pll2,  1,  2),
+	F_GFX3D(450000000, pll15, 1,  2),
 	F_END
 };
 
@@ -3570,6 +3582,12 @@
 	F_END
 };
 
+static unsigned long fmax_gfx3d_8064ab[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 128000000,
+	[VDD_DIG_NOMINAL] = 325000000,
+	[VDD_DIG_HIGH]    = 450000000
+};
+
 static unsigned long fmax_gfx3d_8064[MAX_VDD_LEVELS] __initdata = {
 	[VDD_DIG_LOW]     = 128000000,
 	[VDD_DIG_NOMINAL] = 325000000,
@@ -4295,6 +4313,7 @@
 	F_VCODEC(133330000, pll2, 1,  6),
 	F_VCODEC(200000000, pll2, 1,  4),
 	F_VCODEC(228570000, pll2, 2,  7),
+	F_VCODEC(266670000, pll2, 1,  3),
 	F_END
 };
 
@@ -4325,6 +4344,12 @@
 	},
 };
 
+static unsigned long fmax_vcodec_8064v2[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 100000000,
+	[VDD_DIG_NOMINAL] = 200000000,
+	[VDD_DIG_HIGH]    = 266670000,
+};
+
 #define F_VPE(f, s, d) \
 	{ \
 		.freq_hz = f, \
@@ -5065,6 +5090,8 @@
 		writel_relaxed(0x80|BVAL(5, 3, clk_sel), GCC_APCS_CLK_DIAG);
 		measure->sample_ticks = 0x4000;
 		measure->multiplier = 2;
+		if (cpu_is_krait_v3())
+			measure->multiplier = 8;
 		break;
 	default:
 		ret = -EPERM;
@@ -5450,6 +5477,10 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
 			   "msm-dai-q6.16384"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.16384"),
@@ -5793,6 +5824,10 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
 			   "msm-dai-q6.16384"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.16384"),
@@ -6125,6 +6160,10 @@
 	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
 			   "msm-dai-q6.5"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
 			   "msm-dai-q6.16384"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
 			   "msm-dai-q6.16384"),
@@ -6290,7 +6329,7 @@
 		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
 	}
 
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		rmwreg(0x00000001, AHB_EN3_REG, 0x00000001);
 
 	/* Deassert all locally-owned MM AHB resets. */
@@ -6313,7 +6352,7 @@
 	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
 	rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
 
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
 	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
 		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
@@ -6351,7 +6390,8 @@
 	rmwreg(0x80FF0000, VFE_CC_REG,        0xE0FF4010);
 	rmwreg(0x800000FF, VFE_CC2_REG,       0xE00000FF);
 	rmwreg(0x80FF0000, VPE_CC_REG,        0xE0FF0010);
-	if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()) {
+	if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
+		 || cpu_is_apq8064ab()) {
 		rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
 		rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
 		rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
@@ -6369,7 +6409,7 @@
 		rmwreg(0x80FF0000, GFX2D0_CC_REG,     0xE0FF0010);
 		rmwreg(0x80FF0000, GFX2D1_CC_REG,     0xE0FF0010);
 	}
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		rmwreg(0x00000000, TV_CC_REG,         0x00004010);
 		rmwreg(0x80FF0000, VCAP_CC_REG,       0xE0FF1010);
 	}
@@ -6380,7 +6420,7 @@
 	 * and wake-up value to max.
 	 */
 	rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
 		rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
 	}
@@ -6402,7 +6442,8 @@
 
 	/* Source the dsi_byte_clks from the DSI PHY PLLs */
 	rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
-	if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064())
+	if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
+		|| cpu_is_apq8064ab())
 		rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
 
 	/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
@@ -6412,7 +6453,7 @@
 	 * Source the sata_phy_ref_clk from PXO and set predivider of
 	 * sata_pmalive_clk to 1.
 	 */
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
 		rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
 	}
@@ -6421,7 +6462,7 @@
 	 * TODO: Programming below PLLs and prng_clk is temporary and
 	 *	 needs to be removed after bootloaders program them.
 	 */
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		u32 is_pll_enabled;
 
 		/* Program pxo_src_clk to source from PXO */
@@ -6433,9 +6474,6 @@
 			/* Ref clk = 27MHz and program pll14 to 480MHz */
 			configure_sr_pll(&pll14_config, &pll14_regs, 1);
 
-		/* Program PLL15 to 975MHz with ref clk = 27MHz */
-		configure_sr_pll(&pll15_config, &pll15_regs, 0);
-
 		/* Check if PLL4 is active */
 		is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
 		if (!is_pll_enabled)
@@ -6450,6 +6488,17 @@
 			writel_relaxed(0x2B, PRNG_CLK_NS_REG);
 	}
 
+	if (cpu_is_apq8064()) {
+		/* Program PLL15 to 975MHz with ref clk = 27MHz */
+		configure_sr_pll(&pll15_config, &pll15_regs, 0);
+	} else if (cpu_is_apq8064ab()) {
+		/* Program PLL15 to 900MHZ */
+		pll15_config.l = 0x21 | BVAL(31, 7, 0x620);
+		pll15_config.m = 0x1;
+		pll15_config.n = 0x3;
+		configure_sr_pll(&pll15_config, &pll15_regs, 0);
+	}
+
 	/*
 	 * Program PLL15 to 900MHz with ref clk = 27MHz and
 	 * only enable PLL main output.
@@ -6470,7 +6519,7 @@
 	/* Initialize clock registers. */
 	reg_init();
 
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
 
 	/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
@@ -6512,13 +6561,32 @@
 	}
 	/*
 	 * Change the freq tables for and voltage requirements for
-	 * clocks which differ between 8960 and 8064.
+	 * clocks which differ between chips.
 	 */
 	if (cpu_is_apq8064()) {
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
 
 		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064,
 		       sizeof(gfx3d_clk.c.fmax));
+	}
+	if (cpu_is_apq8064ab()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
+
+		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064ab,
+		       sizeof(gfx3d_clk.c.fmax));
+	}
+	if ((cpu_is_apq8064() &&
+		SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
+		cpu_is_apq8064ab()) {
+
+		memcpy(vcodec_clk.c.fmax, fmax_vcodec_8064v2,
+			sizeof(vcodec_clk.c.fmax));
+		memcpy(ce3_src_clk.c.fmax, fmax_ce3_8064v2,
+			sizeof(ce3_src_clk.c.fmax));
+		memcpy(sdc1_clk.c.fmax, fmax_sdc1_8064v2,
+			sizeof(sdc1_clk.c.fmax));
+	}
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		memcpy(ijpeg_clk.c.fmax, fmax_ijpeg_8064,
 		       sizeof(ijpeg_clk.c.fmax));
 		memcpy(mdp_clk.c.fmax, fmax_mdp_8064,
@@ -6594,7 +6662,7 @@
 	clk_set_rate(&tsif_ref_clk.c, 105000);
 	clk_set_rate(&tssc_clk.c, 27000000);
 	clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
 		clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
 	}
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 26e6ca6..10de231 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2183,6 +2183,18 @@
 	},
 };
 
+struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+	.cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+	.parent = &usb30_master_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sys_noc_usb3_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+	},
+};
+
 static struct branch_clk gcc_usb30_master_clk = {
 	.cbcr_reg = USB30_MASTER_CBCR,
 	.bcr_reg = USB_30_BCR,
@@ -2193,6 +2205,7 @@
 		.dbg_name = "gcc_usb30_master_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(gcc_usb30_master_clk.c),
+		.depends = &gcc_sys_noc_usb3_axi_clk.c,
 	},
 };
 
@@ -2207,18 +2220,6 @@
 	},
 };
 
-struct branch_clk gcc_sys_noc_usb3_axi_clk = {
-	.cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
-	.parent = &usb30_master_clk_src.c,
-	.has_sibling = 1,
-	.base = &virt_bases[GCC_BASE],
-	.c = {
-		.dbg_name = "gcc_sys_noc_usb3_axi_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
-	},
-};
-
 struct branch_clk gcc_usb30_sleep_clk = {
 	.cbcr_reg = USB30_SLEEP_CBCR,
 	.has_sibling = 1,
@@ -5039,6 +5040,7 @@
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
 
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9967000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.spi"),
 	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
@@ -5047,8 +5049,8 @@
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, "f9967000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, "f9966000.spi"),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
@@ -5128,7 +5130,9 @@
 	CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
 	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, ""),
-	CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
+	CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
+		"fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
@@ -5139,8 +5143,10 @@
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
 	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
 	CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index e942173..8bd4433 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -218,6 +218,28 @@
 	.release	= seq_release,
 };
 
+static int clock_parent_show(struct seq_file *m, void *unused)
+{
+	struct clk *clock = m->private;
+	struct clk *parent = clk_get_parent(clock);
+
+	seq_printf(m, "%s\n", (parent ? parent->dbg_name : "None"));
+
+	return 0;
+}
+
+static int clock_parent_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, clock_parent_show, inode->i_private);
+}
+
+static const struct file_operations clock_parent_fops = {
+	.open		= clock_parent_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 static struct dentry *debugfs_base;
 static u32 debug_suspend;
 
@@ -274,6 +296,10 @@
 				S_IRUGO, clk_dir, clock, &fmax_rates_fops))
 			goto error;
 
+	if (!debugfs_create_file("parent", S_IRUGO, clk_dir, clock,
+				&clock_parent_fops))
+			goto error;
+
 	return 0;
 error:
 	debugfs_remove_recursive(clk_dir);
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 1ea18f4..c30bd79 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -72,15 +72,14 @@
 /* Vote for a voltage level. */
 int vote_vdd_level(struct clk_vdd_class *vdd_class, int level)
 {
-	unsigned long flags;
 	int rc;
 
-	spin_lock_irqsave(&vdd_class->lock, flags);
+	mutex_lock(&vdd_class->lock);
 	vdd_class->level_votes[level]++;
 	rc = update_vdd(vdd_class);
 	if (rc)
 		vdd_class->level_votes[level]--;
-	spin_unlock_irqrestore(&vdd_class->lock, flags);
+	mutex_unlock(&vdd_class->lock);
 
 	return rc;
 }
@@ -88,10 +87,9 @@
 /* Remove vote for a voltage level. */
 int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level)
 {
-	unsigned long flags;
 	int rc = 0;
 
-	spin_lock_irqsave(&vdd_class->lock, flags);
+	mutex_lock(&vdd_class->lock);
 	if (WARN(!vdd_class->level_votes[level],
 			"Reference counts are incorrect for %s level %d\n",
 			vdd_class->class_name, level))
@@ -101,7 +99,7 @@
 	if (rc)
 		vdd_class->level_votes[level]++;
 out:
-	spin_unlock_irqrestore(&vdd_class->lock, flags);
+	mutex_unlock(&vdd_class->lock);
 	return rc;
 }
 
@@ -135,6 +133,18 @@
 	unvote_vdd_level(clk->vdd_class, level);
 }
 
+/* Returns true if the rate is valid without voting for it */
+static bool is_rate_valid(struct clk *clk, unsigned long rate)
+{
+	int level;
+
+	if (!clk->vdd_class)
+		return true;
+
+	level = find_vdd_level(clk, rate);
+	return level >= 0;
+}
+
 int clk_prepare(struct clk *clk)
 {
 	int ret = 0;
@@ -333,14 +343,16 @@
 		/* Enforce vdd requirements for target frequency. */
 		rc = vote_rate_vdd(clk, rate);
 		if (rc)
-			goto err_vote_vdd;
+			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 {
+	} else if (is_rate_valid(clk, rate)) {
 		rc = clk->ops->set_rate(clk, rate);
+	} else {
+		rc = -EINVAL;
 	}
 
 	if (!rc)
@@ -351,7 +363,6 @@
 
 err_set_rate:
 	unvote_rate_vdd(clk, rate);
-err_vote_vdd:
 	goto out;
 }
 EXPORT_SYMBOL(clk_set_rate);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e66881b..e8baf6a 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -99,6 +99,23 @@
 /* Address of PCIE20 */
 #define PCIE20_PHYS   0x1b500000
 #define PCIE20_SIZE   SZ_4K
+#define MSM8064_PC_CNTR_PHYS	(APQ8064_IMEM_PHYS + 0x664)
+#define MSM8064_PC_CNTR_SIZE		0x40
+
+static struct resource msm8064_resources_pccntr[] = {
+	{
+		.start	= MSM8064_PC_CNTR_PHYS,
+		.end	= MSM8064_PC_CNTR_PHYS + MSM8064_PC_CNTR_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8064_pc_cntr = {
+	.name		= "pc-cntr",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8064_resources_pccntr),
+	.resource	= msm8064_resources_pccntr,
+};
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
@@ -1945,6 +1962,11 @@
 		.end    = 0x10008000 + SZ_256 - 1,
 		.flags  = IORESOURCE_MEM,
 	},
+	{
+		.start	= GSS_A5_WDOG_EXPIRED,
+		.end	= GSS_A5_WDOG_EXPIRED,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm_gss = {
@@ -2350,17 +2372,18 @@
 
 /* Sensors DSPS platform data */
 
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
-#define PPSS_DSPS_PIPE_BASE     0x12800000
-#define PPSS_DSPS_PIPE_SIZE     0x4000
-#define PPSS_DSPS_DDR_BASE      0x8fe00000
-#define PPSS_DSPS_DDR_SIZE      0x100000
-#define PPSS_SMEM_BASE          0x80000000
-#define PPSS_SMEM_SIZE          0x200000
-#define PPSS_REG_PHYS_BASE	0x12080000
+#define PPSS_DSPS_TCM_CODE_BASE   0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE   0x28000
+#define PPSS_DSPS_TCM_BUF_BASE    0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE    0x4000
+#define PPSS_DSPS_PIPE_BASE       0x12800000
+#define PPSS_DSPS_PIPE_SIZE       0x4000
+#define PPSS_DSPS_DDR_BASE        0x8fe00000
+#define PPSS_DSPS_DDR_SIZE        0x100000
+#define PPSS_SMEM_BASE            0x80000000
+#define PPSS_SMEM_SIZE            0x200000
+#define PPSS_REG_PHYS_BASE        0x12080000
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
 
 static struct dsps_clk_info dsps_clks[] = {};
 static struct dsps_regulator_info dsps_regs[] = {};
@@ -2388,6 +2411,7 @@
 	.ddr_size = PPSS_DSPS_DDR_SIZE,
 	.smem_start = PPSS_SMEM_BASE,
 	.smem_size  = PPSS_SMEM_SIZE,
+	.ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
 	.signature = DSPS_SIGNATURE,
 };
 
@@ -2636,32 +2660,50 @@
 };
 
 static struct msm_dcvs_freq_entry apq8064_freq[] = {
-	{ 384000, 166981,  345600},
-	{ 702000, 213049,  632502},
-	{1026000, 285712,  925613},
-	{1242000, 383945, 1176550},
-	{1458000, 419729, 1465478},
-	{1512000, 434116, 1546674},
-
+	{ 384000, 900,  0, 0, 0},
+	{ 594000, 950,  0, 0, 0},
+	{ 702000, 975,  0, 0, 0},
+	{1026000, 1075, 0, 0, 0},
+	{1242000, 1150, 0, 100, 100},
+	{1458000, 1188, 0, 100, 100},
+	{1512000, 1200, 1, 100, 100},
 };
 
 static struct msm_dcvs_core_info apq8064_core_info = {
-	.freq_tbl = &apq8064_freq[0],
-	.core_param = {
-		.max_time_us = 100000,
-		.num_freq = ARRAY_SIZE(apq8064_freq),
+	.freq_tbl	= &apq8064_freq[0],
+	.core_param	= {
+		.core_type	= MSM_DCVS_CORE_TYPE_CPU,
 	},
-	.algo_param = {
-		.slack_time_us = 58000,
-		.scale_slack_time = 0,
-		.scale_slack_time_pct = 0,
-		.disable_pc_threshold = 1458000,
-		.em_window_size = 100000,
-		.em_max_util_pct = 97,
-		.ss_window_size = 1000000,
-		.ss_util_pct = 95,
-		.ss_iobusy_conv = 100,
+	.algo_param	= {
+		.disable_pc_threshold		= 1458000,
+		.em_win_size_min_us		= 100000,
+		.em_win_size_max_us		= 300000,
+		.em_max_util_pct		= 97,
+		.group_id			= 1,
+		.max_freq_chg_time_us		= 100000,
+		.slack_mode_dynamic		= 0,
+		.slack_weight_thresh_pct	= 3,
+		.slack_time_min_us		= 45000,
+		.slack_time_max_us		= 45000,
+		.ss_iobusy_conv			= 100,
+		.ss_win_size_min_us		= 1000000,
+		.ss_win_size_max_us		= 1000000,
+		.ss_util_pct			= 95,
 	},
+	.energy_coeffs	= {
+		.active_coeff_a		= 336,
+		.active_coeff_b		= 0,
+		.active_coeff_c		= 0,
+
+		.leakage_coeff_a	= -17720,
+		.leakage_coeff_b	= 37,
+		.leakage_coeff_c	= 3329,
+		.leakage_coeff_d	= -277,
+	},
+	.power_param	= {
+		.current_temp	= 25,
+		.num_freq	= ARRAY_SIZE(apq8064_freq),
+	}
 };
 
 struct platform_device apq8064_msm_gov_device = {
@@ -2672,6 +2714,23 @@
 	},
 };
 
+static struct msm_mpd_algo_param apq8064_mpd_algo_param = {
+	.em_win_size_min_us	= 10000,
+	.em_win_size_max_us	= 100000,
+	.em_max_util_pct	= 90,
+	.online_util_pct_min	= 60,
+	.slack_time_min_us	= 50000,
+	.slack_time_max_us	= 100000,
+};
+
+struct platform_device apq8064_msm_mpd_device = {
+	.name	= "msm_mpdecision",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &apq8064_mpd_algo_param,
+	},
+};
+
 #ifdef CONFIG_MSM_VCAP
 #define VCAP_HW_BASE         0x05900000
 
@@ -2715,8 +2774,8 @@
 	{
 		.src = MSM_BUS_MASTER_VIDEO_CAP,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 1920 * 1080 * 3 * 60,
-		.ib = 1920 * 1080 * 3 * 60 * 1.5,
+		.ab = 1920 * 1080 * 10 * 60,
+		.ib = 1920 * 1080 * 10 * 60 * 1.5,
 	},
 };
 
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index ad89a86..d062ff4 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,6 @@
 #include <mach/msm_iomap.h>
 #include <mach/irqs-8930.h>
 #include <mach/rpm.h>
-#include <mach/msm_dcvs.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #include <mach/board.h>
@@ -37,6 +36,23 @@
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
 #endif
+#define MSM8930_PC_CNTR_PHYS	(MSM8930_IMEM_PHYS + 0x664)
+#define MSM8930_PC_CNTR_SIZE		0x40
+
+static struct resource msm8930_resources_pccntr[] = {
+	{
+		.start	= MSM8930_PC_CNTR_PHYS,
+		.end	= MSM8930_PC_CNTR_PHYS + MSM8930_PC_CNTR_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8930_pc_cntr = {
+	.name		= "pc-cntr",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8930_resources_pccntr),
+	.resource	= msm8930_resources_pccntr,
+};
 
 struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
 	.reg_base_addrs = {
@@ -577,43 +593,6 @@
 	},
 };
 
-static struct msm_dcvs_freq_entry msm8930_freq[] = {
-	{ 384000, 166981,  345600},
-	{ 702000, 213049,  632502},
-	{1026000, 285712,  925613},
-	{1242000, 383945, 1176550},
-	{1458000, 419729, 1465478},
-	{1512000, 434116, 1546674},
-
-};
-
-static struct msm_dcvs_core_info msm8930_core_info = {
-	.freq_tbl = &msm8930_freq[0],
-	.core_param = {
-		.max_time_us = 100000,
-		.num_freq = ARRAY_SIZE(msm8930_freq),
-	},
-	.algo_param = {
-		.slack_time_us = 58000,
-		.scale_slack_time = 0,
-		.scale_slack_time_pct = 0,
-		.disable_pc_threshold = 1458000,
-		.em_window_size = 100000,
-		.em_max_util_pct = 97,
-		.ss_window_size = 1000000,
-		.ss_util_pct = 95,
-		.ss_iobusy_conv = 100,
-	},
-};
-
-struct platform_device msm8930_msm_gov_device = {
-	.name = "msm_dcvs_gov",
-	.id = -1,
-	.dev = {
-		.platform_data = &msm8930_core_info,
-	},
-};
-
 struct platform_device msm_bus_8930_sys_fabric = {
 	.name  = "msm_bus_fabric",
 	.id    =  MSM_BUS_FAB_SYSTEM,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 64b901f..72da3d8 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -103,6 +103,24 @@
 #define MSM8960_HSUSB_PHYS		0x12500000
 #define MSM8960_HSUSB_SIZE		SZ_4K
 
+#define MSM8960_PC_CNTR_PHYS	(MSM8960_IMEM_PHYS + 0x664)
+#define MSM8960_PC_CNTR_SIZE		0x40
+
+static struct resource msm8960_resources_pccntr[] = {
+	{
+		.start	= MSM8960_PC_CNTR_PHYS,
+		.end	= MSM8960_PC_CNTR_PHYS + MSM8960_PC_CNTR_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_pc_cntr = {
+	.name		= "pc-cntr",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8960_resources_pccntr),
+	.resource	= msm8960_resources_pccntr,
+};
+
 static struct resource resources_otg[] = {
 	{
 		.start	= MSM8960_HSUSB_PHYS,
@@ -1426,6 +1444,11 @@
 		.end    = 0x03204000 + SZ_256 - 1,
 		.flags  = IORESOURCE_MEM,
 	},
+	{
+		.start  = RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
+		.end    = RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm_8960_riva = {
@@ -2917,46 +2940,89 @@
 };
 
 static struct msm_dcvs_freq_entry grp3d_freq[] = {
-	{0, 0, 333932},
-	{0, 0, 497532},
-	{0, 0, 707610},
-	{0, 0, 844545},
+	{0, 900, 0, 0, 0},
+	{0, 950, 0, 0, 0},
+	{0, 950, 0, 0, 0},
+	{0, 1200, 1, 100, 100},
 };
 
 static struct msm_dcvs_freq_entry grp2d_freq[] = {
-	{0, 0, 86000},
-	{0, 0, 200000},
+	{0, 900, 0, 0, 0},
+	{0, 950, 1, 100, 100},
 };
 
 static struct msm_dcvs_core_info grp3d_core_info = {
-	.freq_tbl = &grp3d_freq[0],
-	.core_param = {
-		.max_time_us = 100000,
-		.num_freq = ARRAY_SIZE(grp3d_freq),
+	.freq_tbl	= &grp3d_freq[0],
+	.core_param	= {
+		.core_type	= MSM_DCVS_CORE_TYPE_GPU,
 	},
-	.algo_param = {
-		.slack_time_us = 39000,
-		.disable_pc_threshold = 86000,
-		.ss_window_size = 1000000,
-		.ss_util_pct = 95,
-		.em_max_util_pct = 97,
-		.ss_iobusy_conv = 100,
+	.algo_param	= {
+		.disable_pc_threshold		= 0,
+		.em_win_size_min_us		= 100000,
+		.em_win_size_max_us		= 300000,
+		.em_max_util_pct		= 97,
+		.group_id			= 0,
+		.max_freq_chg_time_us		= 100000,
+		.slack_mode_dynamic		= 0,
+		.slack_weight_thresh_pct	= 0,
+		.slack_time_min_us		= 39000,
+		.slack_time_max_us		= 39000,
+		.ss_win_size_min_us		= 1000000,
+		.ss_win_size_max_us		= 1000000,
+		.ss_util_pct			= 95,
+		.ss_iobusy_conv			= 100,
 	},
+	.energy_coeffs	= {
+		.active_coeff_a		= 2492,
+		.active_coeff_b		= 0,
+		.active_coeff_c		= 0,
+
+		.leakage_coeff_a	= -17720,
+		.leakage_coeff_b	= 37,
+		.leakage_coeff_c	= 2729,
+		.leakage_coeff_d	= -277,
+	},
+	.power_param	= {
+		.current_temp	= 25,
+		.num_freq	= ARRAY_SIZE(grp3d_freq),
+	}
 };
 
 static struct msm_dcvs_core_info grp2d_core_info = {
-	.freq_tbl = &grp2d_freq[0],
-	.core_param = {
-		.max_time_us = 100000,
-		.num_freq = ARRAY_SIZE(grp2d_freq),
+	.freq_tbl	= &grp2d_freq[0],
+	.core_param	= {
+		.core_type	= MSM_DCVS_CORE_TYPE_GPU,
 	},
-	.algo_param = {
-		.slack_time_us = 39000,
-		.disable_pc_threshold = 90000,
-		.ss_window_size = 1000000,
-		.ss_util_pct = 90,
-		.em_max_util_pct = 95,
+	.algo_param	= {
+		.disable_pc_threshold		= 0,
+		.em_win_size_min_us		= 100000,
+		.em_win_size_max_us		= 300000,
+		.em_max_util_pct		= 97,
+		.group_id			= 0,
+		.max_freq_chg_time_us		= 100000,
+		.slack_mode_dynamic		= 0,
+		.slack_weight_thresh_pct	= 0,
+		.slack_time_min_us		= 39000,
+		.slack_time_max_us		= 39000,
+		.ss_win_size_min_us		= 1000000,
+		.ss_win_size_max_us		= 1000000,
+		.ss_util_pct			= 95,
+		.ss_iobusy_conv			= 100,
 	},
+	.energy_coeffs	= {
+		.active_coeff_a		= 2492,
+		.active_coeff_b		= 0,
+		.active_coeff_c		= 0,
+
+		.leakage_coeff_a	= -17720,
+		.leakage_coeff_b	= 37,
+		.leakage_coeff_c	= 2729,
+		.leakage_coeff_d	= -277,
+	},
+	.power_param	= {
+		.current_temp	= 25,
+		.num_freq	= ARRAY_SIZE(grp2d_freq),
+	}
 };
 
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -3705,17 +3771,18 @@
 /* Sensors DSPS platform data */
 #ifdef CONFIG_MSM_DSPS
 
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE  0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE  0x4000
-#define PPSS_DSPS_PIPE_BASE     0x12800000
-#define PPSS_DSPS_PIPE_SIZE     0x4000
-#define PPSS_DSPS_DDR_BASE      0x8fe00000
-#define PPSS_DSPS_DDR_SIZE      0x100000
-#define PPSS_SMEM_BASE          0x80000000
-#define PPSS_SMEM_SIZE          0x200000
-#define PPSS_REG_PHYS_BASE	0x12080000
+#define PPSS_DSPS_TCM_CODE_BASE   0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE   0x28000
+#define PPSS_DSPS_TCM_BUF_BASE    0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE    0x4000
+#define PPSS_DSPS_PIPE_BASE       0x12800000
+#define PPSS_DSPS_PIPE_SIZE       0x4000
+#define PPSS_DSPS_DDR_BASE        0x8fe00000
+#define PPSS_DSPS_DDR_SIZE        0x100000
+#define PPSS_SMEM_BASE            0x80000000
+#define PPSS_SMEM_SIZE            0x200000
+#define PPSS_REG_PHYS_BASE        0x12080000
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
 
 static struct dsps_clk_info dsps_clks[] = {};
 static struct dsps_regulator_info dsps_regs[] = {};
@@ -3743,6 +3810,7 @@
 	.ddr_size = PPSS_DSPS_DDR_SIZE,
 	.smem_start = PPSS_SMEM_BASE,
 	.smem_size  = PPSS_SMEM_SIZE,
+	.ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
 	.signature = DSPS_SIGNATURE,
 };
 
@@ -4013,43 +4081,6 @@
 	},
 };
 
-static struct msm_dcvs_freq_entry msm8960_freq[] = {
-	{ 384000, 166981,  345600},
-	{ 702000, 213049,  632502},
-	{1026000, 285712,  925613},
-	{1242000, 383945, 1176550},
-	{1458000, 419729, 1465478},
-	{1512000, 434116, 1546674},
-
-};
-
-static struct msm_dcvs_core_info msm8960_core_info = {
-	.freq_tbl = &msm8960_freq[0],
-	.core_param = {
-		.max_time_us = 100000,
-		.num_freq = ARRAY_SIZE(msm8960_freq),
-	},
-	.algo_param = {
-		.slack_time_us = 58000,
-		.scale_slack_time = 0,
-		.scale_slack_time_pct = 0,
-		.disable_pc_threshold = 1458000,
-		.em_window_size = 100000,
-		.em_max_util_pct = 97,
-		.ss_window_size = 1000000,
-		.ss_util_pct = 95,
-		.ss_iobusy_conv = 100,
-	},
-};
-
-struct platform_device msm8960_msm_gov_device = {
-	.name = "msm_dcvs_gov",
-	.id = -1,
-	.dev = {
-		.platform_data = &msm8960_core_info,
-	},
-};
-
 static struct resource msm_cache_erp_resources[] = {
 	{
 		.name = "l1_irq",
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 0a9bbf6..46853ac 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1316,8 +1316,8 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010D204,
-	.phys_size = SZ_8K,
+	.phys_addr_base = 0x0010DD04,
+	.phys_size = SZ_256,
 };
 
 struct platform_device msm9615_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index acf577e..6434a63 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -1017,13 +1017,13 @@
 				ARRAY_SIZE(msm_iommu_gfx2d_devs));
 	}
 
-	if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
+	if (cpu_is_apq8064() || cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
 		platform_add_devices(msm_iommu_jpegd_devs,
 				ARRAY_SIZE(msm_iommu_jpegd_devs));
 		platform_add_devices(msm_iommu_adreno3xx_gfx_devs,
 				ARRAY_SIZE(msm_iommu_adreno3xx_gfx_devs));
 	}
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		platform_add_devices(msm_iommu_vcap_devs,
 				ARRAY_SIZE(msm_iommu_vcap_devs));
 
@@ -1039,14 +1039,14 @@
 				ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
 	}
 
-	if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
+	if (cpu_is_apq8064() || cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
 		platform_add_devices(msm_iommu_jpegd_ctx_devs,
 				ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
 
 		platform_add_devices(msm_iommu_adreno3xx_ctx_devs,
 				ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs));
 	}
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		platform_add_devices(msm_iommu_vcap_ctx_devs,
 			ARRAY_SIZE(msm_iommu_vcap_ctx_devs));
 
@@ -1081,12 +1081,12 @@
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
 			platform_device_unregister(msm_iommu_jpegd_devs[i]);
 	}
-	if (cpu_is_apq8064()) {
+	if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_ctx_devs); i++)
 			platform_device_unregister(msm_iommu_vcap_ctx_devs[i]);
 	}
 
-	if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
+	if (cpu_is_apq8064() || cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs);
 			   i++)
 			platform_device_unregister(
@@ -1097,7 +1097,7 @@
 			platform_device_unregister(
 				msm_iommu_jpegd_ctx_devs[i]);
 
-		if (cpu_is_apq8064()) {
+		if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
 			for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_devs);
 			   i++)
 				platform_device_unregister(
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 343ea76..50ab26f 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -1664,12 +1664,13 @@
  * These are various Vdd levels supported by PMIC
  */
 static uint32_t msm_c2_pmic_mv[] __initdata = {
-	1300000, 1287500, 1275000, 1262500, 1250000,
-	1237500, 1225000, 1212500, 1200000, 1187500,
-	1175000, 1162500, 1150000, 1137500, 1125000,
-	1112500, 1100000, 1087500, 1075000, 1062500,
-	1050000, 1037500, 1025000, 1012500, 0, 0, 0,
-	0, 0, 0, 0, 1000,
+	1350000, 1337500, 1325000, 1312500, 1300000,
+	1287500, 1275000, 1262500, 1250000, 1237500,
+	1225000, 1212500, 1200000, 1187500, 1175000,
+	1162500, 1150000, 1137500, 1125000, 1112500,
+	1100000, 1087500, 1075000, 1062500, 0,
+	0,	 0,	  0,	   0,	    0,
+	0, 1050000,
 };
 
 /**
@@ -1709,9 +1710,9 @@
 			.step_quot = ~0,
 			.tgt_volt_offset = 0,
 			.turbo_Vmax = 1350000,
-			.turbo_Vmin = 950000,
+			.turbo_Vmin = 1100000,
 			.nom_Vmax = 1350000,
-			.nom_Vmin = 950000,
+			.nom_Vmin = 1100000,
 			.calibrated_uV = 1300000,
 	},
 };
@@ -1729,7 +1730,7 @@
 	uint32_t quot;
 
 	/* This formula is as per chip characterization data */
-	quot = max_quot - (((max_freq - new_freq) * 5) / 10);
+	quot = max_quot - (((max_freq - new_freq) * 7) / 10);
 
 	return quot;
 }
@@ -1749,7 +1750,7 @@
 
 static struct msm_cpr_config msm_cpr_pdata = {
 	.ref_clk_khz = 19200,
-	.delay_us = 25000,
+	.delay_us = 1000,
 	.irq_line = 0,
 	.cpr_mode_data = msm_cpr_mode_data,
 	.tgt_count_div_N = 1,
@@ -1757,7 +1758,7 @@
 	.ceiling = 40,
 	.sw_vlevel = 20,
 	.up_threshold = 1,
-	.dn_threshold = 2,
+	.dn_threshold = 4,
 	.up_margin = 0,
 	.dn_margin = 0,
 	.max_nom_freq = 700800,
@@ -1819,6 +1820,22 @@
 	 * enough to represent the value of maximum quot
 	 */
 	msm_cpr_pdata.max_quot = cpr_info->turbo_quot * 10 + 600;
+	/**
+	 * Fused Quot value for 1.2GHz on a 1.2GHz part is lower than
+	 * the quot value calculated using the scaling factor formula for
+	 * 1.2GHz when running on a 1.4GHz part. So, prop up the Quot for
+	 * a 1.2GHz part by a chip characterization recommended value.
+	 * Ditto for a 1.0GHz part.
+	 */
+	if (msm8625_cpu_id() == MSM8625A) {
+		msm_cpr_pdata.max_quot += 100;
+		if (msm_cpr_pdata.max_quot > 1400)
+			msm_cpr_pdata.max_quot = 1400;
+	} else if (msm8625_cpu_id() == MSM8625) {
+		msm_cpr_pdata.max_quot += 120;
+		if (msm_cpr_pdata.max_quot > 1350)
+			msm_cpr_pdata.max_quot = 1350;
+	}
 
 	/**
 	 * Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
@@ -2022,6 +2039,7 @@
 
 static struct notifier_block panic_handler = {
 	.notifier_call = msm7627a_panic_handler,
+	.priority = INT_MAX,
 };
 
 static int __init panic_register(void)
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8b59b14..614037c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -33,6 +33,6 @@
 void __init msm8x25_spm_device_init(void);
 void __init msm_pm_register_cpr_ops(void);
 void __init msm8x25_kgsl_3d0_init(void);
-void __iomem *core1_reset_base(void);
+void __iomem *core_reset_base(unsigned int);
 extern void setup_mm_for_reboot(void);
 #endif
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 7bffd9b..37cdc98 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -192,7 +192,9 @@
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
 }
 
-#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+#define MSM_LPASS_QDSP6SS_PHYS		0x28800000
+#define MSM_LPASS_QDSP6SS_WDOG_PHYS	0x28882000
+#define MSM_LPASS_QDSP6SS_IM_PHYS	0x288A0000
 
 static struct resource msm_8660_q6_resources[] = {
 	{
@@ -200,6 +202,21 @@
 		.end    = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
 		.flags  = IORESOURCE_MEM,
 	},
+	{
+		.start  = MSM_LPASS_QDSP6SS_IM_PHYS,
+		.end    = MSM_LPASS_QDSP6SS_IM_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM_LPASS_QDSP6SS_WDOG_PHYS,
+		.end    = MSM_LPASS_QDSP6SS_WDOG_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start	= LPASS_Q6SS_WDOG_EXPIRED,
+		.end	= LPASS_Q6SS_WDOG_EXPIRED,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm_pil_q6v3 = {
@@ -210,6 +227,7 @@
 };
 
 #define MSM_MSS_REGS_PHYS 0x10200000
+#define MSM_MSS_WDOG_PHYS 0x10020000
 
 static struct resource msm_8660_modem_resources[] = {
 	{
@@ -217,6 +235,16 @@
 		.end    = MSM_MSS_REGS_PHYS + SZ_256 - 1,
 		.flags  = IORESOURCE_MEM,
 	},
+	{
+		.start	= MSM_MSS_WDOG_PHYS,
+		.end	= MSM_MSS_WDOG_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MARM_WDOG_EXPIRED,
+		.end	= MARM_WDOG_EXPIRED,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm_pil_modem = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index e66bf27..6f3dda3 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/devices.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, 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
@@ -109,6 +109,10 @@
 extern struct platform_device msm_device_sdc3;
 extern struct platform_device msm_device_sdc4;
 
+extern struct platform_device msm8960_pc_cntr;
+extern struct platform_device msm8064_pc_cntr;
+extern struct platform_device msm8930_pc_cntr;
+
 extern struct platform_device msm_device_gadget_peripheral;
 extern struct platform_device msm_device_hsusb_host;
 extern struct platform_device msm_device_hsusb_host2;
@@ -394,8 +398,6 @@
 extern struct platform_device msm8930_cpu_idle_device;
 extern struct platform_device apq8064_cpu_idle_device;
 
-extern struct platform_device msm8960_msm_gov_device;
-extern struct platform_device msm8930_msm_gov_device;
 extern struct platform_device apq8064_msm_gov_device;
 
 extern struct platform_device msm_bus_8930_apps_fabric;
@@ -443,6 +445,8 @@
 extern struct platform_device msm8960ab_device_acpuclk;
 extern struct platform_device msm9615_device_acpuclk;
 
+extern struct platform_device apq8064_msm_mpd_device;
+
 extern struct platform_device msm_gpio_device;
 
 extern struct platform_device apq_cpudai_mi2s;
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
deleted file mode 100644
index e528650..0000000
--- a/arch/arm/mach-msm/gss-8064.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-
-#include <mach/irqs.h>
-#include <mach/msm_smsm.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-#include <mach/socinfo.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-static struct gss_8064_data {
-	struct miscdevice gss_dev;
-	void *pil_handle;
-	void *gss_ramdump_dev;
-	void *smem_ramdump_dev;
-} gss_data;
-
-static int crash_shutdown;
-
-static struct subsys_device *gss_8064_dev;
-
-#define MAX_SSR_REASON_LEN 81U
-
-static void log_gss_sfr(void)
-{
-	u32 size;
-	char *smem_reason, reason[MAX_SSR_REASON_LEN];
-
-	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
-	if (!smem_reason || !size) {
-		pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
-		return;
-	}
-	if (!smem_reason[0]) {
-		pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
-		return;
-	}
-
-	size = min(size, MAX_SSR_REASON_LEN-1);
-	memcpy(reason, smem_reason, size);
-	reason[size] = '\0';
-	pr_err("GSS subsystem failure reason: %s.\n", reason);
-
-	smem_reason[0] = '\0';
-	wmb();
-}
-
-static void restart_gss(void)
-{
-	log_gss_sfr();
-	subsystem_restart_dev(gss_8064_dev);
-}
-
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
-{
-	/* Ignore if we're the one that set SMSM_RESET */
-	if (crash_shutdown)
-		return;
-
-	if (new_state & SMSM_RESET) {
-		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
-			"Probable err_fatal on the GSS. "
-			"Calling subsystem restart...\n");
-		restart_gss();
-	}
-}
-
-#define Q6_FW_WDOG_ENABLE		0x08882024
-#define Q6_SW_WDOG_ENABLE		0x08982024
-static int gss_shutdown(const struct subsys_desc *desc)
-{
-	pil_force_shutdown("gss");
-	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
-
-	return 0;
-}
-
-static int gss_powerup(const struct subsys_desc *desc)
-{
-	pil_force_boot("gss");
-	enable_irq(GSS_A5_WDOG_EXPIRED);
-	return 0;
-}
-
-void gss_crash_shutdown(const struct subsys_desc *desc)
-{
-	crash_shutdown = 1;
-	smsm_reset_modem(SMSM_RESET);
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment gss_segments[] = {
-	{0x89000000, 0x00D00000}
-};
-
-static struct ramdump_segment smem_segments[] = {
-	{0x80000000, 0x00200000},
-};
-
-static int gss_ramdump(int enable,
-				const struct subsys_desc *crashed_subsys)
-{
-	int ret = 0;
-
-	if (enable) {
-		ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
-			ARRAY_SIZE(gss_segments));
-
-		if (ret < 0) {
-			pr_err("Unable to dump gss memory (rc = %d).\n",
-			       ret);
-			goto out;
-		}
-
-		ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
-			ARRAY_SIZE(smem_segments));
-
-		if (ret < 0) {
-			pr_err("Unable to dump smem memory (rc = %d).\n", ret);
-			goto out;
-		}
-	}
-
-out:
-	return ret;
-}
-
-static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
-{
-	pr_err("Watchdog bite received from GSS!\n");
-	restart_gss();
-
-	return IRQ_HANDLED;
-}
-
-static struct subsys_desc gss_8064 = {
-	.name = "gss",
-	.shutdown = gss_shutdown,
-	.powerup = gss_powerup,
-	.ramdump = gss_ramdump,
-	.crash_shutdown = gss_crash_shutdown
-};
-
-static int gss_subsystem_restart_init(void)
-{
-	gss_8064_dev = subsys_register(&gss_8064);
-	if (IS_ERR(gss_8064_dev))
-		return PTR_ERR(gss_8064_dev);
-	return 0;
-}
-
-static int gss_open(struct inode *inode, struct file *filep)
-{
-	void *ret;
-	gss_data.pil_handle = ret = pil_get("gss");
-	if (!ret)
-		pr_debug("%s - pil_get returned NULL\n", __func__);
-	return 0;
-}
-
-static int gss_release(struct inode *inode, struct file *filep)
-{
-	pil_put(gss_data.pil_handle);
-	pr_debug("%s pil_put called on GSS\n", __func__);
-	return 0;
-}
-
-const struct file_operations gss_file_ops = {
-	.open = gss_open,
-	.release = gss_release,
-};
-
-static int __init gss_8064_init(void)
-{
-	int ret;
-
-	if (!cpu_is_apq8064())
-		return -ENODEV;
-
-	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
-		smsm_state_cb, 0);
-
-	if (ret < 0)
-		pr_err("%s: Unable to register SMSM callback! (%d)\n",
-				__func__, ret);
-
-	ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
-			IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
-
-	if (ret < 0) {
-		pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
-				__func__, ret);
-		disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
-		goto out;
-	}
-
-	ret = gss_subsystem_restart_init();
-
-	if (ret < 0) {
-		pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
-				__func__, ret);
-		goto out;
-	}
-
-	gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
-	gss_data.gss_dev.name = "gss";
-	gss_data.gss_dev.fops = &gss_file_ops;
-	ret = misc_register(&gss_data.gss_dev);
-
-	if (ret) {
-		pr_err("%s: misc_registers failed for %s (%d)", __func__,
-				gss_data.gss_dev.name, ret);
-		goto out;
-	}
-
-	gss_data.gss_ramdump_dev = create_ramdump_device("gss");
-
-	if (!gss_data.gss_ramdump_dev) {
-		pr_err("%s: Unable to create gss ramdump device. (%d)\n",
-				__func__, -ENOMEM);
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	gss_data.smem_ramdump_dev = create_ramdump_device("smem-gss");
-
-	if (!gss_data.smem_ramdump_dev) {
-		pr_err("%s: Unable to create smem ramdump device. (%d)\n",
-				__func__, -ENOMEM);
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	pr_info("%s: gss fatal driver init'ed.\n", __func__);
-out:
-	return ret;
-}
-
-module_init(gss_8064_init);
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index e5ad312..0537421 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -35,8 +35,6 @@
 	 * we've been released from the holding pen: secondary_stack
 	 * should now contain the SVC stack for this core
 	 */
-	mvn	r7, #0			@ -1 to registers
-	str r7,[r6]			@ back to the pen for ack
 	b	secondary_startup
 ENDPROC(msm_secondary_startup)
 
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index d1d9f4b..f296aae 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -43,7 +43,7 @@
 {
 }
 
-static inline void platform_do_lowpower(unsigned int cpu)
+static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
 {
 	/* Just enter wfi for now. TODO: Properly shut off the cpu. */
 	for (;;) {
@@ -53,9 +53,6 @@
 			/*
 			 * OK, proper wakeup, we're done
 			 */
-			pen_release = -1;
-			dmac_flush_range((char *)&pen_release,
-				(char *)&pen_release + sizeof(pen_release));
 			break;
 		}
 
@@ -67,9 +64,7 @@
 		 * possible, since we are currently running incoherently, and
 		 * therefore cannot safely call printk() or anything else
 		 */
-		dmac_inv_range((char *)&pen_release,
-			       (char *)&pen_release + sizeof(pen_release));
-		pr_debug("CPU%u: spurious wakeup call\n", cpu);
+		(*spurious)++;
 	}
 }
 
@@ -85,6 +80,8 @@
  */
 void platform_cpu_die(unsigned int cpu)
 {
+	int spurious = 0;
+
 	if (unlikely(cpu != smp_processor_id())) {
 		pr_crit("%s: running on %u, should be %u\n",
 			__func__, smp_processor_id(), cpu);
@@ -95,10 +92,13 @@
 	 * we're ready for shutdown now, so do it
 	 */
 	cpu_enter_lowpower();
-	platform_do_lowpower(cpu);
+	platform_do_lowpower(cpu, &spurious);
 
 	pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__);
 	cpu_leave_lowpower();
+
+	if (spurious)
+		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
 }
 
 int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index cf36388..f5a158f 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -95,6 +95,7 @@
 	VFE_MSG_OUTPUT_SECONDARY,
 	VFE_MSG_OUTPUT_TERTIARY1,
 	VFE_MSG_OUTPUT_TERTIARY2,
+	VFE_MSG_V2X_LIVESHOT_PRIMARY,
 };
 
 enum vpe_resp_msg {
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 0da0b33..770713d 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -20,6 +20,7 @@
 #include <linux/list.h>
 #include <linux/clkdev.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <mach/clk.h>
 
 /*
@@ -53,7 +54,7 @@
 	int (*set_vdd)(struct clk_vdd_class *v_class, int level);
 	int level_votes[MAX_VDD_LEVELS];
 	unsigned long cur_level;
-	spinlock_t lock;
+	struct mutex lock;
 };
 
 #define DEFINE_VDD_CLASS(_name, _set_vdd) \
@@ -61,7 +62,7 @@
 		.class_name = #_name, \
 		.set_vdd = _set_vdd, \
 		.cur_level = ARRAY_SIZE(_name.level_votes), \
-		.lock = __SPIN_LOCK_UNLOCKED(lock) \
+		.lock = __MUTEX_INITIALIZER(_name.lock) \
 	}
 
 enum handoff {
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index b14f145..f63af64 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -38,6 +38,8 @@
 /* Maximum number of SMT entries allowed by the system */
 #define MAX_NUM_SMR	128
 
+#define MAX_NUM_BFB_REGS	32
+
 /**
  * struct msm_iommu_dev - a single IOMMU hardware instance
  * name		Human-readable name given to this IOMMU HW instance
@@ -64,6 +66,17 @@
 	int mids[MAX_NUM_MIDS];
 };
 
+/**
+ * struct msm_iommu_bfb_settings - a set of IOMMU BFB tuning parameters
+ * regs		An array of register offsets to configure
+ * data		Values to write to corresponding registers
+ * length	Number of valid entries in the offset/val arrays
+ */
+struct msm_iommu_bfb_settings {
+	unsigned int regs[MAX_NUM_BFB_REGS];
+	unsigned int data[MAX_NUM_BFB_REGS];
+	int length;
+};
 
 /**
  * struct msm_iommu_drvdata - A single IOMMU hardware instance
@@ -76,6 +89,7 @@
  * @name:	Human-readable name of this IOMMU device
  * @gdsc:	Regulator needed to power this HW block (v2 only)
  * @nsmr:	Size of the SMT on this HW block (v2 only)
+ * @bfb_settings: Optional BFB performance tuning parameters
  *
  * A msm_iommu_drvdata holds the global driver data about a single piece
  * of an IOMMU hardware instance.
@@ -90,6 +104,7 @@
 	const char *name;
 	struct regulator *gdsc;
 	unsigned int nsmr;
+	struct msm_iommu_bfb_settings *bfb_settings;
 };
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
index b01dbd8..c4991bf 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
@@ -15,6 +15,8 @@
 
 #define CTX_SHIFT  12
 #define CTX_OFFSET 0x8000
+#define IMPLDEF_OFFSET	0x2000
+#define IMPLDEF_LENGTH	0xDFF
 
 #define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
 #define GET_CTX_REG(reg, base, ctx) \
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index 413a778..2ec0e21 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -87,6 +87,8 @@
 #define MSM8625_INT_CPR_IRQ0		(GIC_SPI_START + 32 + 25)
 #define MSM8625_INT_CPR_IRQ1		(GIC_SPI_START + 32 + 26)
 #define MSM8625_INT_CPR_IRQ2		(GIC_SPI_START + 32 + 27)
+#define MSM8625_INT_ACSR_MP_CORE_IPC2	(GIC_SPI_START + 32 + 28)
+#define MSM8625_INT_ACSR_MP_CORE_IPC3	(GIC_SPI_START + 32 + 29)
 
 #define MSM8625_INT_ADSP_A11_SMSM	MSM8625_INT_ADSP_A11
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8974.h b/arch/arm/mach-msm/include/mach/irqs-8974.h
index d10b537..8152eca 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -24,9 +24,7 @@
 #define GIC_PPI_START 16
 #define GIC_SPI_START 32
 
-#define AVS_SVICINT				(GIC_PPI_START + 6)
-#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
-#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 7)
 /* PPI 15 is unused */
 
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 6ec12c1..fd63fd2 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -33,6 +33,7 @@
 	const unsigned int ramdump_timeout_ms;
 	int image_upgrade_supported;
 	struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
+	int send_shdn;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index fa7e6f0..490a34b 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,8 @@
 #define CORE_NAME_MAX (32)
 #define CORES_MAX (10)
 
+#define CPU_OFFSET	1  /* used to notify TZ the core number */
+
 enum msm_core_idle_state {
 	MSM_DCVS_IDLE_ENTER,
 	MSM_DCVS_IDLE_EXIT,
@@ -88,15 +90,16 @@
  * before the sink driver can be registered.
  */
 struct msm_dcvs_core_info {
-	struct msm_dcvs_freq_entry *freq_tbl;
-	struct msm_dcvs_core_param core_param;
-	struct msm_dcvs_algo_param algo_param;
+	struct msm_dcvs_freq_entry		*freq_tbl;
+	struct msm_dcvs_core_param		core_param;
+	struct msm_dcvs_algo_param		algo_param;
+	struct msm_dcvs_energy_curve_coeffs	energy_coeffs;
+	struct msm_dcvs_power_params		power_param;
 };
 
 /**
  * msm_dcvs_register_core
  * @core_name: Unique name identifier for the core.
- * @group_id: Cores that are to be grouped for synchronized frequency scaling
  * @info: The core specific algorithm parameters.
  * @return :
  *	0 on success,
@@ -106,9 +109,8 @@
  * Register the core with msm_dcvs driver. Done once at init before calling
  * msm_dcvs_freq_sink_register
  * Cores that need to run synchronously must share the same group id.
- * If a core doesnt care to be in any group, the group_id should be 0.
  */
-extern int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
+extern int msm_dcvs_register_core(const char *core_name,
 		struct msm_dcvs_core_info *info);
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
index 3cc2595..597fdc0 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,38 +13,87 @@
 #ifndef _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
 #define _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
 
+enum msm_dcvs_core_type {
+	MSM_DCVS_CORE_TYPE_CPU = 0,
+	MSM_DCVS_CORE_TYPE_GPU = 1,
+};
+
+enum msm_dcvs_algo_param_type {
+	MSM_DCVS_ALGO_DCVS_PARAM = 0,
+	MSM_DCVS_ALGO_MPD_PARAM  = 1,
+};
+
 enum msm_dcvs_scm_event {
-	MSM_DCVS_SCM_IDLE_ENTER,
-	MSM_DCVS_SCM_IDLE_EXIT,
-	MSM_DCVS_SCM_QOS_TIMER_EXPIRED,
-	MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
-	MSM_DCVS_SCM_ENABLE_CORE,
-	MSM_DCVS_SCM_RESET_CORE,
+	MSM_DCVS_SCM_IDLE_ENTER = 0, /* Core enters idle */
+	MSM_DCVS_SCM_IDLE_EXIT = 1, /* Core exits idle */
+	MSM_DCVS_SCM_QOS_TIMER_EXPIRED = 2, /* Core slack timer expired */
+	MSM_DCVS_SCM_CLOCK_FREQ_UPDATE = 3, /* Core freq change complete */
+	MSM_DCVS_SCM_CORE_ONLINE = 4, /* Core is online */
+	MSM_DCVS_SCM_CORE_OFFLINE = 5, /* Core is offline */
+	MSM_DCVS_SCM_CORE_UNAVAILABLE = 6, /* Core is offline + unavailable */
+	MSM_DCVS_SCM_DCVS_ENABLE = 7, /* DCVS is enabled/disabled for core */
+	MSM_DCVS_SCM_MPD_ENABLE = 8, /* Enable/disable MP Decision */
+	MSM_DCVS_SCM_RUNQ_UPDATE = 9, /* Update running threads */
+	MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED = 10, /* MPDecision slack timer */
 };
 
 struct msm_dcvs_algo_param {
-	uint32_t slack_time_us;
-	uint32_t scale_slack_time;
-	uint32_t scale_slack_time_pct;
 	uint32_t disable_pc_threshold;
-	uint32_t em_window_size;
+	uint32_t em_win_size_min_us;
+	uint32_t em_win_size_max_us;
 	uint32_t em_max_util_pct;
-	uint32_t ss_window_size;
-	uint32_t ss_util_pct;
+	uint32_t group_id;
+	uint32_t max_freq_chg_time_us;
+	uint32_t slack_mode_dynamic;
+	uint32_t slack_time_min_us;
+	uint32_t slack_time_max_us;
+	uint32_t slack_weight_thresh_pct;
 	uint32_t ss_iobusy_conv;
+	uint32_t ss_win_size_min_us;
+	uint32_t ss_win_size_max_us;
+	uint32_t ss_util_pct;
 };
 
 struct msm_dcvs_freq_entry {
-	uint32_t freq; /* Core freq in MHz */
-	uint32_t idle_energy;
-	uint32_t active_energy;
+	uint32_t freq;
+	uint32_t voltage;
+	uint32_t is_trans_level;
+	uint32_t active_energy_offset;
+	uint32_t leakage_energy_offset;
 };
 
-struct msm_dcvs_core_param {
-	uint32_t max_time_us;
+struct msm_dcvs_energy_curve_coeffs {
+	int32_t active_coeff_a;
+	int32_t active_coeff_b;
+	int32_t active_coeff_c;
+
+	int32_t leakage_coeff_a;
+	int32_t leakage_coeff_b;
+	int32_t leakage_coeff_c;
+	int32_t leakage_coeff_d;
+};
+
+struct msm_dcvs_power_params {
+	uint32_t current_temp;
 	uint32_t num_freq; /* number of msm_dcvs_freq_entry passed */
 };
 
+struct msm_dcvs_core_param {
+	uint32_t core_type;
+	uint32_t core_bitmask_id;
+};
+
+struct msm_mpd_algo_param {
+	uint32_t em_win_size_min_us;
+	uint32_t em_win_size_max_us;
+	uint32_t em_max_util_pct;
+	uint32_t mp_em_rounding_point_min;
+	uint32_t mp_em_rounding_point_max;
+	uint32_t online_util_pct_min;
+	uint32_t online_util_pct_max;
+	uint32_t slack_time_min_us;
+	uint32_t slack_time_max_us;
+};
 
 #ifdef CONFIG_MSM_DCVS
 /**
@@ -61,20 +110,9 @@
 extern int msm_dcvs_scm_init(size_t size);
 
 /**
- * Create an empty core group
- *
- * @return:
- *	0 on success.
- *	-ENOMEM: Insufficient memory.
- *	-EINVAL: Invalid args.
- */
-extern int msm_dcvs_scm_create_group(uint32_t id);
-
-/**
- * Registers cores as part of a group
+ * Registers cores with the DCVS algo.
  *
  * @core_id: The core identifier that will be used for communication with DCVS
- * @group_id: The group to which this core will be added to.
  * @param: The core parameters
  * @freq: Array of frequency and energy values
  *
@@ -83,9 +121,8 @@
  *	-ENOMEM: Insufficient memory.
  *	-EINVAL: Invalid args.
  */
-extern int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
-		struct msm_dcvs_core_param *param,
-		struct msm_dcvs_freq_entry *freq);
+extern int msm_dcvs_scm_register_core(uint32_t core_id,
+		struct msm_dcvs_core_param *param);
 
 /**
  * Set DCVS algorithm parameters
@@ -101,6 +138,33 @@
 		struct msm_dcvs_algo_param *param);
 
 /**
+ * Set MPDecision algorithm parameters
+ *
+ * @param: The param data structure
+ *	0 on success.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_mpd_scm_set_algo_params(struct msm_mpd_algo_param *param);
+
+/**
+ * Set frequency and power characteristics for the core.
+ *
+ * @param core_id: The core identifier that will be used to interace with the
+ *                 DCVS algo.
+ * @param pwr_param: power params
+ * @param freq_entry: frequency characteristics desired
+ * @param coeffs: Coefficients that will describe the power curve
+ *
+ * @return int
+ *	0 on success.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_set_power_params(uint32_t core_id,
+				struct msm_dcvs_power_params *pwr_param,
+				struct msm_dcvs_freq_entry *freq_entry,
+				struct msm_dcvs_energy_curve_coeffs *coeffs);
+
+/**
  * Do an SCM call.
  *
  * @core_id: The core identifier.
@@ -126,19 +190,44 @@
  *		@param1: time taken in usec to switch to the frequency
  *		@ret0: New QoS timer value for the core in usec
  *		@ret1: unused
- *	MSM_DCVS_SCM_ENABLE_CORE
- *		@param0: enable(1) or disable(0) core
- *		@param1: active clock frequency of the core in KHz
- *		@ret0: New clock frequency for the core in KHz
- *		@ret1: unused
- *	MSM_DCVS_SCM_RESET_CORE
+ *	MSM_DCVS_SCM_CORE_ONLINE
  *		@param0: active clock frequency of the core in KHz
+ *		@param1: time taken to online the core
+ *		@ret0: unused
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_CORE_OFFLINE
+ *		@param0: time taken to offline the core
+ *		@param1: unused
+ *		@ret0: unused
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_CORE_UNAVAILABLE
+ *		@param0: TODO:bitmask
+ *		@param1: unused
+ *		@ret0: Bitmask of cores to bring online/offline.
+ *		@ret1: Mp Decision slack time. Common to all cores.
+ *	MSM_DCVS_SCM_DCVS_ENABLE
+ *		@param0: 1 to enable; 0 to disable DCVS
  *		@param1: unused
  *		@ret0: New clock frequency for the core in KHz
  *		@ret1: unused
- * @return:
- *	0 on success,
- *	SCM return values
+ *	MSM_DCVS_SCM_MPD_ENABLE
+ *		@param0: 1 to enable; 0 to disable MP Decision
+ *		@param1: unused
+ *		@ret0: unused
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_RUNQ_UPDATE
+ *		@param0: run q value
+ *		@param1: unused
+ *		@ret0: Bitmask of cores online
+ *		@ret1: New QoS timer for MP Decision (usec)
+ *	MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED
+ *		@param0: unused
+ *		@param1: unused
+ *		@ret0: Bitmask of cores online
+ *		@ret1: New QoS timer for MP Decision (usec)
+ *	@return:
+ *		0 on success,
+ *		SCM return values
  */
 extern int msm_dcvs_scm_event(uint32_t core_id,
 		enum msm_dcvs_scm_event event_id,
@@ -148,16 +237,21 @@
 #else
 static inline int msm_dcvs_scm_init(uint32_t phy, size_t bytes)
 { return -ENOSYS; }
-static inline int msm_dcvs_scm_create_group(uint32_t id)
-{ return -ENOSYS; }
 static inline int msm_dcvs_scm_register_core(uint32_t core_id,
-		uint32_t group_id,
 		struct msm_dcvs_core_param *param,
 		struct msm_dcvs_freq_entry *freq)
 { return -ENOSYS; }
 static inline int msm_dcvs_scm_set_algo_params(uint32_t core_id,
 		struct msm_dcvs_algo_param *param)
 { return -ENOSYS; }
+static inline int msm_mpd_scm_set_algo_params(
+		struct msm_mpd_algo_param *param)
+{ return -ENOSYS; }
+static inline int msm_dcvs_set_power_params(uint32_t core_id,
+		struct msm_dcvs_power_params *pwr_param,
+		struct msm_dcvs_freq_entry *freq_entry,
+		struct msm_dcvs_energy_curve_coeffs *coeffs)
+{ return -ENOSYS; }
 static inline int msm_dcvs_scm_event(uint32_t core_id,
 		enum msm_dcvs_scm_event event_id,
 		uint32_t param0, uint32_t param1,
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index 0f9dba6..a876798 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -86,6 +86,7 @@
  * @smem_start - start of the smem region as physical address
  * @smem_size - size of the smem region in bytes
  * @ppss_pause_reg - Offset to the PPSS_PAUSE register
+ * @ppss_wdog_unmasked_int_en_reg - Offset to PPSS_WDOG_UNMASKED_INT_EN register
  * @signature - signature for validity check.
  */
 struct msm_dsps_platform_data {
@@ -109,6 +110,7 @@
 	int smem_start;
 	int smem_size;
 	int ppss_pause_reg;
+	int ppss_wdog_unmasked_int_en_reg;
 	u32 signature;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
index 4e22b0f..c6eb527 100644
--- a/arch/arm/mach-msm/include/mach/msm_hsusb.h
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -138,6 +138,7 @@
 
 	int self_powered;
 	int is_phy_status_timer_on;
+	bool prop_chg;
 };
 
 struct msm_otg_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
index dec8a58..732aaff 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
@@ -23,7 +23,7 @@
  *
  */
 
-#define MPQ8092_SHARED_RAM_PHYS	0x0FA00000
+#define MPQ8092_MSM_SHARED_RAM_PHYS	0x0FA00000
 
 #define MPQ8092_QGIC_DIST_PHYS	0xF9000000
 #define MPQ8092_QGIC_DIST_SIZE	SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
index eecdd67..765de13 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -34,9 +34,27 @@
 #define MSM9625_TLMM_PHYS	0xFD510000
 #define MSM9625_TLMM_SIZE	SZ_16K
 
+/*
+ * TODO: Revert IMEM_PHYS back to actual
+ * address 0xfe807800
+ * after IMEM issues resolved.
+ *
+ */
+#define MSM9625_IMEM_PHYS	0xFC42B000
+#define MSM9625_IMEM_SIZE	SZ_2K
+
 #ifdef CONFIG_DEBUG_MSM9625_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
 #endif
 
+/*
+ * IMEM is retained for secure watchdog reset
+ * Debug Image looks at actual IMEM to
+ * do memory dumping.
+ */
+
+#define MSM9625_DBG_IMEM_PHYS	0xFE807800
+#define MSM9625_DBG_IMEM_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 6f925d4..8dbd29c 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -101,7 +101,7 @@
 #define MSM_DBG_IMEM_BASE	IOMEM(0xFB600000)	/*  4K */
 
 #define MSM_STRONGLY_ORDERED_PAGE	0xFA0F0000
-#define MSM8625_SECONDARY_PHYS		0x0FE00000
+#define MSM8625_CPU_PHYS		0x0FE00000
 
 
 #if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 133a1b3..44b52b6 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -57,8 +57,7 @@
 #define SMSM_PWRC              0x00000200
 #define SMSM_TIMEWAIT          0x00000400
 #define SMSM_TIMEINIT          0x00000800
-#define SMSM_PWRC_EARLY_EXIT   0x00001000
-#define SMSM_LTE_COEX_AWAKE    0x00001000
+#define SMSM_PROC_AWAKE        0x00001000
 #define SMSM_WFPI              0x00002000
 #define SMSM_SLEEP             0x00004000
 #define SMSM_SLEEPEXIT         0x00008000
@@ -97,47 +96,6 @@
 
 #define SMSM_SUBSYS2AP_STATUS         0x00008000
 
-#ifdef CONFIG_MSM_SMD
-void *smem_alloc(unsigned id, unsigned size);
-#else
-void *smem_alloc(unsigned id, unsigned size)
-{
-	return NULL;
-}
-#endif
-void *smem_alloc2(unsigned id, unsigned size_in);
-void *smem_get_entry(unsigned id, unsigned *size);
-int smsm_change_state(uint32_t smsm_entry,
-		      uint32_t clear_mask, uint32_t set_mask);
-
-/*
- * Changes the global interrupt mask.  The set and clear masks are re-applied
- * every time the global interrupt mask is updated for callback registration
- * and de-registration.
- *
- * The clear mask is applied first, so if a bit is set to 1 in both the clear
- * mask and the set mask, the result will be that the interrupt is set.
- *
- * @smsm_entry  SMSM entry to change
- * @clear_mask  1 = clear bit, 0 = no-op
- * @set_mask    1 = set bit, 0 = no-op
- *
- * @returns 0 for success, < 0 for error
- */
-int smsm_change_intr_mask(uint32_t smsm_entry,
-			  uint32_t clear_mask, uint32_t set_mask);
-int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
-uint32_t smsm_get_state(uint32_t smsm_entry);
-int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
-	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
-	void *data);
-int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
-	void (*notify)(void *, uint32_t, uint32_t), void *data);
-void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
-	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
-void smsm_reset_modem(unsigned mode);
-void smsm_reset_modem_cont(void);
-void smd_sleep_exit(void);
 
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
 #define SMEM_NUM_SMD_BLOCK_CHANNELS         64
@@ -250,8 +208,128 @@
 	SMSM_NUM_INTR_MUX = 8,
 };
 
+#ifdef CONFIG_MSM_SMD
+void *smem_alloc(unsigned id, unsigned size);
+void *smem_alloc2(unsigned id, unsigned size_in);
+void *smem_get_entry(unsigned id, unsigned *size);
+int smsm_change_state(uint32_t smsm_entry,
+		      uint32_t clear_mask, uint32_t set_mask);
+
+/*
+ * Changes the global interrupt mask.  The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry  SMSM entry to change
+ * @clear_mask  1 = clear bit, 0 = no-op
+ * @set_mask    1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+int smsm_change_intr_mask(uint32_t smsm_entry,
+			  uint32_t clear_mask, uint32_t set_mask);
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
+uint32_t smsm_get_state(uint32_t smsm_entry);
+int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+	void *data);
+int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t, uint32_t), void *data);
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void smsm_reset_modem(unsigned mode);
+void smsm_reset_modem_cont(void);
+void smd_sleep_exit(void);
+
+
 int smsm_check_for_modem_crash(void);
 void *smem_find(unsigned id, unsigned size);
 void *smem_get_entry(unsigned id, unsigned *size);
+#else
+static inline void *smem_alloc(unsigned id, unsigned size)
+{
+	return NULL;
+}
 
+static inline void *smem_alloc2(unsigned id, unsigned size_in)
+{
+	return NULL;
+}
+
+static inline void *smem_get_entry(unsigned id, unsigned *size)
+{
+	return NULL;
+}
+
+static inline int smsm_change_state(uint32_t smsm_entry,
+		      uint32_t clear_mask, uint32_t set_mask)
+{
+	return -ENODEV;
+}
+
+/*
+ * Changes the global interrupt mask.  The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry  SMSM entry to change
+ * @clear_mask  1 = clear bit, 0 = no-op
+ * @set_mask    1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+static inline int smsm_change_intr_mask(uint32_t smsm_entry,
+			  uint32_t clear_mask, uint32_t set_mask)
+{
+	return -ENODEV;
+}
+
+static inline int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask)
+{
+	return -ENODEV;
+}
+static inline uint32_t smsm_get_state(uint32_t smsm_entry)
+{
+	return 0;
+}
+static inline int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+	void *data)
+{
+	return -ENODEV;
+}
+static inline int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t, uint32_t), void *data)
+{
+	return -ENODEV;
+}
+static inline void smsm_print_sleep_info(uint32_t sleep_delay,
+	uint32_t sleep_limit, uint32_t irq_mask, uint32_t wakeup_reason,
+	uint32_t pending_irqs)
+{
+}
+static inline void smsm_reset_modem(unsigned mode)
+{
+}
+static inline void smsm_reset_modem_cont(void)
+{
+}
+static inline void smd_sleep_exit(void)
+{
+}
+static inline int smsm_check_for_modem_crash(void)
+{
+	return -ENODEV;
+}
+static inline void *smem_find(unsigned id, unsigned size)
+{
+	return NULL;
+}
+#endif
 #endif
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.h b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
similarity index 81%
rename from arch/arm/mach-msm/qdsp6v2/q6core.h
rename to arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
index cb25d6b..ea345fb 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -45,8 +45,18 @@
 	uint32_t power_collapse;
 };
 
+#define ADSP_CMD_SET_DTS_MODEL_ID 0x00012917
+
+struct adsp_dts_modelid {
+	struct apr_hdr hdr;
+	uint32_t  model_ID_size;
+	uint8_t   model_ID[128];
+};
+
 int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps);
 
 uint32_t core_get_adsp_version(void);
 
+uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id);
+
 #endif /* __Q6CORE_H__ */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f6e082d..075d20f 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -32,7 +32,8 @@
 	RPM_VREG_VERSION_9615,
 	RPM_VREG_VERSION_8930,
 	RPM_VREG_VERSION_8930_PM8917,
-	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930_PM8917,
+	RPM_VREG_VERSION_8960_PM8917,
+	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8960_PM8917,
 };
 
 #define RPM_VREG_PIN_CTRL_NONE		0x00
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 546cbaf..225440c 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -89,6 +89,7 @@
 	MSM_CPU_7X25AA,
 	MSM_CPU_7X25AB,
 	MSM_CPU_8064,
+	MSM_CPU_8064AB,
 	MSM_CPU_8930,
 	MSM_CPU_8930AA,
 	MSM_CPU_7X27AA,
@@ -304,6 +305,15 @@
 #endif
 }
 
+static inline int cpu_is_apq8064ab(void)
+{
+#ifdef CONFIG_ARCH_APQ8064
+	return read_msm_cpu_type() == MSM_CPU_8064AB;
+#else
+	return 0;
+#endif
+}
+
 static inline int cpu_is_msm8930(void)
 {
 #ifdef CONFIG_ARCH_MSM8930
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index e0fec65..39ac253 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -462,6 +462,7 @@
 	MSM_CHIP_DEVICE(APCS_GCC, MSM9625),
 	MSM_CHIP_DEVICE(TLMM, MSM9625),
 	MSM_CHIP_DEVICE(TMR, MSM9625),
+	MSM_CHIP_DEVICE(IMEM, MSM9625),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
@@ -470,6 +471,7 @@
 #ifdef CONFIG_DEBUG_MSM9625_UART
 	MSM_DEVICE(DEBUG_UART),
 #endif
+	MSM_CHIP_DEVICE(DBG_IMEM, MSM9625),
 };
 
 void __init msm_map_msm9625_io(void)
@@ -497,7 +499,7 @@
 
 void __init msm_map_mpq8092_io(void)
 {
-	msm_shared_ram_phys = MSM8092_MSM_SHARED_RAM_PHYS;
+	msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
 	msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
 }
 #endif /* CONFIG_ARCH_MPQ8092 */
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
deleted file mode 100644
index be18b68..0000000
--- a/arch/arm/mach-msm/lpass-8660.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-#define Q6SS_WDOG_ENABLE		0x28882024
-#define Q6SS_SOFT_INTR_WAKEUP		0x288A001C
-#define MODULE_NAME			"lpass_8x60"
-#define SCM_Q6_NMI_CMD			0x1
-
-static struct subsys_device *subsys_8x60_q6_dev;
-
-/* Subsystem restart: QDSP6 data, functions */
-static void *q6_ramdump_dev;
-static void q6_fatal_fn(struct work_struct *);
-static DECLARE_WORK(q6_fatal_work, q6_fatal_fn);
-static void __iomem *q6_wakeup_intr;
-
-static void q6_fatal_fn(struct work_struct *work)
-{
-	pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
-	subsystem_restart_dev(subsys_8x60_q6_dev);
-	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
-}
-
-static void send_q6_nmi(void)
-{
-	/* Send NMI to QDSP6 via an SCM call. */
-	scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
-
-	/* Wakeup the Q6 */
-	if (q6_wakeup_intr)
-		writel_relaxed(0x2000, q6_wakeup_intr);
-	else
-		pr_warn("lpass-8660: Unable to send wakeup interrupt to Q6.\n");
-
-	/* Q6 requires atleast 100ms to dump caches etc.*/
-	mdelay(100);
-
-	pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
-}
-
-int subsys_q6_shutdown(const struct subsys_desc *crashed_subsys)
-{
-	void __iomem *q6_wdog_addr =
-		ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
-
-	send_q6_nmi();
-	writel_relaxed(0x0, q6_wdog_addr);
-	/* The write needs to go through before the q6 is shutdown. */
-	mb();
-	iounmap(q6_wdog_addr);
-
-	pil_force_shutdown("q6");
-	disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
-	return 0;
-}
-
-int subsys_q6_powerup(const struct subsys_desc *crashed_subsys)
-{
-	int ret = pil_force_boot("q6");
-	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
-	return ret;
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
-					0x46700000}, {0x28400000, 0x12800} };
-static int subsys_q6_ramdump(int enable,
-				const struct subsys_desc *crashed_subsys)
-{
-	if (enable)
-		return do_ramdump(q6_ramdump_dev, q6_segments,
-				ARRAY_SIZE(q6_segments));
-	else
-		return 0;
-}
-
-void subsys_q6_crash_shutdown(const struct subsys_desc *crashed_subsys)
-{
-	send_q6_nmi();
-}
-
-static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
-{
-	int ret;
-
-	ret = schedule_work(&q6_fatal_work);
-	disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
-	return IRQ_HANDLED;
-}
-
-static struct subsys_desc subsys_8x60_q6 = {
-	.name = "lpass",
-	.shutdown = subsys_q6_shutdown,
-	.powerup = subsys_q6_powerup,
-	.ramdump = subsys_q6_ramdump,
-	.crash_shutdown = subsys_q6_crash_shutdown
-};
-
-static void __exit lpass_fatal_exit(void)
-{
-	subsys_unregister(subsys_8x60_q6_dev);
-	iounmap(q6_wakeup_intr);
-	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-static int __init lpass_fatal_init(void)
-{
-	int ret;
-
-	ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
-			IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
-	if (ret < 0) {
-		pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
-			__func__);
-		goto out;
-	}
-
-	q6_ramdump_dev = create_ramdump_device("lpass");
-
-	if (!q6_ramdump_dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	q6_wakeup_intr = ioremap_nocache(Q6SS_SOFT_INTR_WAKEUP, 8);
-
-	if (!q6_wakeup_intr)
-		pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
-
-	subsys_8x60_q6_dev = subsys_register(&subsys_8x60_q6);
-	if (IS_ERR(subsys_8x60_q6_dev))
-		ret = PTR_ERR(subsys_8x60_q6_dev);
-out:
-	return ret;
-}
-
-module_init(lpass_fatal_init);
-module_exit(lpass_fatal_exit);
-
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index f548417..77eeb53 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -110,8 +110,12 @@
 
 	/* Wait for the modem to complete its power down actions. */
 	for (i = 20; i > 0; i--) {
-		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
+			if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
+				pr_info("%s: mdm2ap_status went low, i = %d\n",
+					__func__, i);
 			break;
+		}
 		msleep(100);
 	}
 	if (i == 0) {
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index ea15a17..58b26f2 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -290,6 +290,17 @@
 		} else
 			pr_debug("%s Image upgrade not supported\n", __func__);
 		break;
+	case SHUTDOWN_CHARM:
+		if (!mdm_drv->pdata->send_shdn)
+			break;
+		mdm_drv->mdm_ready = 0;
+		if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
+			pr_info("Sending shutdown request to mdm\n");
+		ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
+		if (ret)
+			pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
+				   __func__, ret);
+		break;
 	default:
 		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
 		ret = -EINVAL;
@@ -382,6 +393,9 @@
 {
 	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
+	if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0))
+		pr_info("%s: mdm2ap_status went low\n", __func__);
+
 	pr_debug("%s: mdm sent status change interrupt\n", __func__);
 	if (value == 0 && mdm_drv->mdm_ready == 1) {
 		pr_info("%s: unexpected reset external modem\n", __func__);
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index c406b89a..9e865c5 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -14,6 +14,7 @@
 #define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
 
 #define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002)
+#define MDM_DEBUG_MASK_SHDN_LOG     (0x00000004)
 #define GPIO_IS_VALID(gpio) \
 	(gpio != -1)
 struct mdm_modem_drv;
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 74c1c4a..a785389 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -173,63 +173,29 @@
 
 struct reserve_info *reserve_info;
 
-static unsigned long stable_size(struct membank *mb,
-	unsigned long unstable_limit)
-{
-	unsigned long upper_limit = mb->start + mb->size;
-
-	if (!unstable_limit)
-		return mb->size;
-
-	/* Check for 32 bit roll-over */
-	if (upper_limit >= mb->start) {
-		/* If we didn't roll over we can safely make the check below */
-		if (upper_limit <= unstable_limit)
-			return mb->size;
-	}
-
-	if (mb->start >= unstable_limit)
-		return 0;
-	return unstable_limit - mb->start;
-}
-
-/* stable size of all memory banks contiguous to and below this one */
-static unsigned long total_stable_size(unsigned long bank)
-{
-	int i;
-	struct membank *mb = &meminfo.bank[bank];
-	int memtype = reserve_info->paddr_to_memtype(mb->start);
-	unsigned long size;
-
-	size = stable_size(mb, reserve_info->low_unstable_address);
-	for (i = bank - 1, mb = &meminfo.bank[bank - 1]; i >= 0; i--, mb--) {
-		if (mb->start + mb->size != (mb + 1)->start)
-			break;
-		if (reserve_info->paddr_to_memtype(mb->start) != memtype)
-			break;
-		size += stable_size(mb, reserve_info->low_unstable_address);
-	}
-	return size;
-}
-
+/**
+ * calculate_reserve_limits() - calculate reserve limits for all
+ * memtypes
+ *
+ * for each memtype in the reserve_info->memtype_reserve_table, sets
+ * the `limit' field to the largest size of any memblock of that
+ * memtype.
+ */
 static void __init calculate_reserve_limits(void)
 {
-	int i;
-	struct membank *mb;
+	struct memblock_region *mr;
 	int memtype;
 	struct memtype_reserve *mt;
-	unsigned long size;
 
-	for (i = 0, mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++)  {
-		memtype = reserve_info->paddr_to_memtype(mb->start);
+	for_each_memblock(memory, mr) {
+		memtype = reserve_info->paddr_to_memtype(mr->base);
 		if (memtype == MEMTYPE_NONE) {
-			pr_warning("unknown memory type for bank at %lx\n",
-				(long unsigned int)mb->start);
+			pr_warning("unknown memory type for region at %lx\n",
+				(long unsigned int)mr->base);
 			continue;
 		}
 		mt = &reserve_info->memtype_reserve_table[memtype];
-		size = total_stable_size(i);
-		mt->limit = max(mt->limit, size);
+		mt->limit = max_t(unsigned long, mt->limit, mr->size);
 	}
 }
 
@@ -252,50 +218,38 @@
 
 static void __init reserve_memory_for_mempools(void)
 {
-	int i, memtype, membank_type;
+	int memtype, memreg_type;
 	struct memtype_reserve *mt;
-	struct membank *mb;
+	struct memblock_region *mr, *mr_candidate = NULL;
 	int ret;
-	unsigned long size;
 
 	mt = &reserve_info->memtype_reserve_table[0];
 	for (memtype = 0; memtype < MEMTYPE_MAX; memtype++, mt++) {
 		if (mt->flags & MEMTYPE_FLAGS_FIXED || !mt->size)
 			continue;
 
-		/* We know we will find memory bank(s) of the proper size
-		 * as we have limited the size of the memory pool for
-		 * each memory type to the largest total size of the memory
-		 * banks which are contiguous and of the correct memory type.
-		 * Choose the memory bank with the highest physical
+		/* Choose the memory block with the highest physical
 		 * address which is large enough, so that we will not
 		 * take memory from the lowest memory bank which the kernel
 		 * is in (and cause boot problems) and so that we might
 		 * be able to steal memory that would otherwise become
-		 * highmem. However, do not use unstable memory.
+		 * highmem.
 		 */
-		for (i = meminfo.nr_banks - 1; i >= 0; i--) {
-			mb = &meminfo.bank[i];
-			membank_type =
-				reserve_info->paddr_to_memtype(mb->start);
-			if (memtype != membank_type)
+		for_each_memblock(memory, mr) {
+			memreg_type =
+				reserve_info->paddr_to_memtype(mr->base);
+			if (memtype != memreg_type)
 				continue;
-			size = total_stable_size(i);
-			if (size >= mt->size) {
-				size = stable_size(mb,
-					reserve_info->low_unstable_address);
-				if (!size)
-					continue;
-				/* mt->size may be larger than size, all this
-				 * means is that we are carving the memory pool
-				 * out of multiple contiguous memory banks.
-				 */
-				mt->start = mb->start + (size - mt->size);
-				ret = memblock_remove(mt->start, mt->size);
-				BUG_ON(ret);
-				break;
-			}
+			if (mr->size >= mt->size
+				&& (mr_candidate == NULL
+					|| mr->base > mr_candidate->base))
+				mr_candidate = mr;
 		}
+		BUG_ON(mr_candidate == NULL);
+		/* bump mt up against the top of the region */
+		mt->start = mr_candidate->base + mr_candidate->size - mt->size;
+		ret = memblock_remove(mt->start, mt->size);
+		BUG_ON(ret);
 	}
 }
 
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
deleted file mode 100644
index 096ed9c..0000000
--- a/arch/arm/mach-msm/modem-8660.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-#define MODEM_HWIO_MSS_RESET_ADDR       0x00902C48
-#define MODULE_NAME			"modem_8660"
-#define MODEM_WDOG_ENABLE		0x10020008
-#define MODEM_CLEANUP_DELAY_MS		20
-
-#define SUBSYS_FATAL_DEBUG
-
-#if defined(SUBSYS_FATAL_DEBUG)
-static void debug_crash_modem_fn(struct work_struct *);
-static int reset_modem;
-static int ignore_smsm_ack;
-
-static DECLARE_DELAYED_WORK(debug_crash_modem_work,
-				debug_crash_modem_fn);
-
-module_param(reset_modem, int, 0644);
-#endif
-
-static struct subsys_device *modem_8660_dev;
-
-/* Subsystem restart: Modem data, functions */
-static void *modem_ramdump_dev;
-static void modem_fatal_fn(struct work_struct *);
-static void modem_unlock_timeout(struct work_struct *work);
-static int modem_notif_handler(struct notifier_block *this,
-				unsigned long code,
-				void *_cmd);
-static DECLARE_WORK(modem_fatal_work, modem_fatal_fn);
-static DECLARE_DELAYED_WORK(modem_unlock_timeout_work,
-				modem_unlock_timeout);
-
-static struct notifier_block modem_notif_nb = {
-	.notifier_call = modem_notif_handler,
-};
-
-static void modem_unlock_timeout(struct work_struct *work)
-{
-	void __iomem *hwio_modem_reset_addr =
-			ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
-	pr_crit("%s: Timeout waiting for modem to unlock.\n", MODULE_NAME);
-
-	/* Set MSS_MODEM_RESET to 0x0 since the unlock didn't work */
-	writel_relaxed(0x0, hwio_modem_reset_addr);
-	/* Write needs to go through before the modem is restarted. */
-	mb();
-	iounmap(hwio_modem_reset_addr);
-
-	subsystem_restart_dev(modem_8660_dev);
-	enable_irq(MARM_WDOG_EXPIRED);
-}
-
-static void modem_fatal_fn(struct work_struct *work)
-{
-	uint32_t modem_state;
-	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
-	uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
-					SMSM_SYSTEM_PWRDWN_USR;
-
-	pr_err("%s: Watchdog bite received from modem!\n", MODULE_NAME);
-
-	modem_state = smsm_get_state(SMSM_MODEM_STATE);
-	pr_err("%s: Modem SMSM state = 0x%x!", MODULE_NAME, modem_state);
-
-	if (modem_state == 0 || modem_state & panic_smsm_states) {
-
-		subsystem_restart_dev(modem_8660_dev);
-		enable_irq(MARM_WDOG_EXPIRED);
-
-	} else if (modem_state & reset_smsm_states) {
-
-		pr_err("%s: User-invoked system reset/powerdown.",
-			MODULE_NAME);
-		kernel_restart(NULL);
-
-	} else {
-
-		int ret;
-		void *hwio_modem_reset_addr =
-				ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
-
-		pr_err("%s: Modem AHB locked up.\n", MODULE_NAME);
-		pr_err("%s: Trying to free up modem!\n", MODULE_NAME);
-
-		writel_relaxed(0x3, hwio_modem_reset_addr);
-
-		/* If we are still alive after 6 seconds (allowing for
-		 * the 5-second-delayed-panic-reboot), modem is either
-		 * still wedged or SMSM didn't come through. Force panic
-		 * in that case.
-		*/
-		ret = schedule_delayed_work(&modem_unlock_timeout_work,
-					msecs_to_jiffies(6000));
-
-		iounmap(hwio_modem_reset_addr);
-	}
-}
-
-static int modem_notif_handler(struct notifier_block *this,
-				unsigned long code,
-				void *_cmd)
-{
-	if (code == MODEM_NOTIFIER_START_RESET) {
-		if (ignore_smsm_ack) {
-			ignore_smsm_ack = 0;
-			goto out;
-		}
-		pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
-		subsystem_restart_dev(modem_8660_dev);
-	}
-out:
-	return NOTIFY_DONE;
-}
-
-static int modem_shutdown(const struct subsys_desc *crashed_subsys)
-{
-	void __iomem *modem_wdog_addr;
-
-	/* If the modem didn't already crash, setting SMSM_RESET
-	 * here will help flush caches etc. The ignore_smsm_ack
-	 * flag is set to ignore the SMSM_RESET notification
-	 * that is generated due to the modem settings its own
-	 * SMSM_RESET bit in response to the apps setting the
-	 * apps SMSM_RESET bit.
-	 */
-	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
-		ignore_smsm_ack = 1;
-		smsm_reset_modem(SMSM_RESET);
-	}
-
-	/* Disable the modem watchdog to allow clean modem bootup */
-	modem_wdog_addr = ioremap_nocache(MODEM_WDOG_ENABLE, 8);
-	writel_relaxed(0x0, modem_wdog_addr);
-
-	/*
-	 * The write above needs to go through before the modem is
-	 * powered up again (subsystem restart).
-	 */
-	mb();
-	iounmap(modem_wdog_addr);
-
-	/* Wait here to allow the modem to clean up caches etc. */
-	msleep(MODEM_CLEANUP_DELAY_MS);
-	pil_force_shutdown("modem");
-	disable_irq_nosync(MARM_WDOG_EXPIRED);
-
-
-
-	return 0;
-}
-
-static int modem_powerup(const struct subsys_desc *crashed_subsys)
-{
-	int ret;
-
-	ret = pil_force_boot("modem");
-	enable_irq(MARM_WDOG_EXPIRED);
-
-	return ret;
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment modem_segments[] = {
-	{0x42F00000, 0x46000000 - 0x42F00000} };
-
-static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
-{
-	if (enable)
-		return do_ramdump(modem_ramdump_dev, modem_segments,
-			ARRAY_SIZE(modem_segments));
-	else
-		return 0;
-}
-
-static void modem_crash_shutdown(const struct subsys_desc *crashed_subsys)
-{
-	/* If modem hasn't already crashed, send SMSM_RESET. */
-	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
-		modem_unregister_notifier(&modem_notif_nb);
-		smsm_reset_modem(SMSM_RESET);
-	}
-
-	/* Wait to allow the modem to clean up caches etc. */
-	mdelay(5);
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
-	int ret;
-
-	ret = schedule_work(&modem_fatal_work);
-	disable_irq_nosync(MARM_WDOG_EXPIRED);
-
-	return IRQ_HANDLED;
-}
-
-static struct subsys_desc subsys_8660_modem = {
-	.name = "modem",
-	.shutdown = modem_shutdown,
-	.powerup = modem_powerup,
-	.ramdump = modem_ramdump,
-	.crash_shutdown = modem_crash_shutdown
-};
-
-static int __init modem_8660_init(void)
-{
-	int ret;
-
-	/* Need to listen for SMSM_RESET always */
-	modem_register_notifier(&modem_notif_nb);
-
-#if defined(SUBSYS_FATAL_DEBUG)
-	schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(5000));
-#endif
-
-	ret = request_irq(MARM_WDOG_EXPIRED, modem_wdog_bite_irq,
-			IRQF_TRIGGER_RISING, "modem_wdog", NULL);
-
-	if (ret < 0) {
-		pr_err("%s: Unable to request MARM_WDOG_EXPIRED irq.",
-			__func__);
-		goto out;
-	}
-
-	modem_ramdump_dev = create_ramdump_device("modem");
-
-	if (!modem_ramdump_dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	modem_8660_dev = subsys_register(&subsys_8660_modem);
-	if (IS_ERR(modem_8660_dev))
-		ret = PTR_ERR(modem_8660_dev);
-out:
-	return ret;
-}
-
-static void __exit modem_8660_exit(void)
-{
-	subsys_unregister(modem_8660_dev);
-	free_irq(MARM_WDOG_EXPIRED, NULL);
-}
-
-#ifdef SUBSYS_FATAL_DEBUG
-static void debug_crash_modem_fn(struct work_struct *work)
-{
-	if (reset_modem == 1)
-		smsm_reset_modem(SMSM_RESET);
-
-	reset_modem = 0;
-	schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(1000));
-}
-#endif
-
-module_init(modem_8660_init);
-module_exit(modem_8660_exit);
-
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index f0a123b..83b3bc4 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -258,7 +258,7 @@
 {
 	int ret;
 
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		return -ENODEV;
 
 	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
index fec578f..942eca5 100644
--- a/arch/arm/mach-msm/modem-ssr-8974.c
+++ b/arch/arm/mach-msm/modem-ssr-8974.c
@@ -15,10 +15,14 @@
 #include <linux/module.h>
 #include <linux/err.h>
 
+#include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
 
+#include "ramdump.h"
+
 static int crash_shutdown;
+static int modem_ssr_ignore_errors;
 static struct subsys_device *modem_ssr_dev;
 
 #define MAX_SSR_REASON_LEN 81U
@@ -50,6 +54,7 @@
 static void restart_modem(void)
 {
 	log_modem_sfr();
+	modem_ssr_ignore_errors = 1;
 	subsystem_restart("modem");
 }
 
@@ -67,11 +72,21 @@
 
 static int modem_shutdown(const struct subsys_desc *subsys)
 {
+	pil_force_shutdown("modem");
+	pil_force_shutdown("mba");
 	return 0;
 }
 
 static int modem_powerup(const struct subsys_desc *subsys)
 {
+	/*
+	 * At this time, the modem is shutdown. Therefore this function cannot
+	 * run concurrently with either the watchdog bite error handler or the
+	 * SMSM callback, making it safe to unset the flag below.
+	 */
+	modem_ssr_ignore_errors = 0;
+	pil_force_boot("mba");
+	pil_force_boot("modem");
 	return 0;
 }
 
@@ -81,15 +96,53 @@
 	smsm_reset_modem(SMSM_RESET);
 }
 
-static int modem_ramdump(int enable,
-				const struct subsys_desc *crashed_subsys)
+static struct ramdump_segment modem_segments[] = {
+	{0x08400000, 0x0D100000 - 0x08400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x0FA00000, 0x0FC00000 - 0x0FA00000},
+};
+
+static void *modem_ramdump_dev;
+static void *smem_ramdump_dev;
+
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
 {
-	return 0;
+	int ret = 0;
+
+	if (!enable)
+		return ret;
+
+	pil_force_boot("mba");
+
+	ret = do_ramdump(modem_ramdump_dev, modem_segments,
+				ARRAY_SIZE(modem_segments));
+
+	if (ret < 0) {
+		pr_err("Unable to dump modem fw memory (rc = %d).\n",
+			ret);
+		goto out;
+	}
+
+	ret = do_ramdump(smem_ramdump_dev, smem_segments,
+		ARRAY_SIZE(smem_segments));
+
+	if (ret < 0) {
+		pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+		goto out;
+	}
+
+out:
+	pil_force_shutdown("mba");
+	return ret;
 }
 
 static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
 {
-	pr_err("Watchdog bite received from modem software!\n");
+	if (modem_ssr_ignore_errors)
+		return IRQ_HANDLED;
+	pr_err("Watchdog bite received from the modem!\n");
 	restart_modem();
 	return IRQ_HANDLED;
 }
@@ -133,9 +186,27 @@
 		goto out;
 	}
 
+	modem_ramdump_dev = create_ramdump_device("modem");
+
+	if (!modem_ramdump_dev) {
+		pr_err("%s: Unable to create a modem ramdump device.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	smem_ramdump_dev = create_ramdump_device("smem-modem");
+
+	if (!smem_ramdump_dev) {
+		pr_err("%s: Unable to create an smem ramdump device.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
 	pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
 out:
 	return ret;
 }
 
-arch_initcall(modem_8974_init);
+module_init(modem_8974_init);
diff --git a/arch/arm/mach-msm/mpm.c b/arch/arm/mach-msm/mpm.c
index 1c39415..5127607 100644
--- a/arch/arm/mach-msm/mpm.c
+++ b/arch/arm/mach-msm/mpm.c
@@ -388,6 +388,7 @@
 {
 	unsigned long *apps_irq_bitmap;
 	int debug_mask;
+	int i = 0;
 
 	if (from_idle) {
 		apps_irq_bitmap = msm_mpm_enabled_apps_irqs;
@@ -400,15 +401,17 @@
 	}
 
 	if (debug_mask) {
-		static char buf[DIV_ROUND_UP(MSM_MPM_NR_APPS_IRQS, 32)*9+1];
+		i = find_first_bit(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
+		while (i < MSM_MPM_NR_APPS_IRQS) {
+			struct irq_desc *desc = i ?
+				irq_to_desc(i) : NULL;
+			pr_info("%s: cannot monitor irq=%d %s\n",
+			__func__, i, desc->name);
+			i = find_next_bit(apps_irq_bitmap,
+				MSM_MPM_NR_APPS_IRQS, i + 1);
+		}
 
-		bitmap_scnprintf(buf, sizeof(buf), apps_irq_bitmap,
-				MSM_MPM_NR_APPS_IRQS);
-		buf[sizeof(buf) - 1] = '\0';
-
-		pr_info("%s: cannot monitor %s", __func__, buf);
 	}
-
 	return (bool)__bitmap_empty(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
 }
 
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index 12f7d96..c00352d 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -54,6 +53,26 @@
 module_param(enable, bool, 0644);
 MODULE_PARM_DESC(enable, "CPR Enable");
 
+static int msm_cpr_debug_mask;
+module_param_named(
+	debug_mask, msm_cpr_debug_mask, int, S_IRUGO | S_IWUSR
+);
+
+enum {
+	/* configuration log */
+	MSM_CPR_DEBUG_CONFIG = BIT(0),
+	/* step up/down interrupt log */
+	MSM_CPR_DEBUG_STEPS = BIT(1),
+	/* cpu frequency notification log */
+	MSM_CPR_DEBUG_FREQ_TRANS = BIT(2),
+};\
+
+#define msm_cpr_debug(mask, message, ...) \
+	do { \
+		if ((mask) & msm_cpr_debug_mask) \
+			pr_info(message, ##__VA_ARGS__); \
+	} while (0)
+
 struct msm_cpr {
 	int curr_osc;
 	int cpr_mode;
@@ -65,7 +84,9 @@
 	unsigned int irq;
 	uint32_t cur_Vmin;
 	uint32_t cur_Vmax;
+	uint32_t prev_volt_uV;
 	struct mutex cpr_mutex;
+	spinlock_t cpr_lock;
 	struct regulator *vreg_cx;
 	const struct msm_cpr_config *config;
 	struct notifier_block freq_transition;
@@ -133,17 +154,17 @@
 /* Enable the CPR H/W Block */
 static void cpr_enable(struct msm_cpr *cpr)
 {
-	mutex_lock(&cpr->cpr_mutex);
+	spin_lock(&cpr->cpr_lock);
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
-	mutex_unlock(&cpr->cpr_mutex);
+	spin_unlock(&cpr->cpr_lock);
 }
 
 /* Disable the CPR H/W Block */
 static void cpr_disable(struct msm_cpr *cpr)
 {
-	mutex_lock(&cpr->cpr_mutex);
+	spin_lock(&cpr->cpr_lock);
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
-	mutex_unlock(&cpr->cpr_mutex);
+	spin_unlock(&cpr->cpr_lock);
 }
 
 static int32_t cpr_poll_result(struct msm_cpr *cpr)
@@ -154,8 +175,7 @@
 	rc = readl_poll_timeout(cpr->base + RBCPR_RESULT_0, val, ~val & BUSY_M,
 				10, 1000);
 	if (rc)
-		pr_info("%s: RBCPR_RESULT_0 read error: %d\n",
-			 __func__, rc);
+		pr_err("RBCPR_RESULT_0 read error: %d\n", rc);
 	return rc;
 }
 
@@ -167,8 +187,7 @@
 	rc = readl_poll_timeout(cpr->base + RBIF_IRQ_STATUS, val, val & 0x1,
 				10, 1000);
 	if (rc)
-		pr_info("%s: RBCPR_IRQ_STATUS read error: %d\n",
-			 __func__, rc);
+		pr_err("RBCPR_IRQ_STATUS read error: %d\n", rc);
 	return rc;
 }
 
@@ -200,15 +219,16 @@
 	 */
 	level_uV = chip_data->turbo_Vmax -
 		(chip_data->tgt_volt_offset * cpr->vp->step_size);
-	pr_debug("tgt_volt_uV = %d\n", level_uV);
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+		"tgt_volt_uV = %d\n", level_uV);
 
 	/* Call the PMIC specific routine to set the voltage */
 	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
 	if (rc) {
-		pr_err("%s: Initial voltage set at %duV failed. %d\n",
-			__func__, level_uV, rc);
+		pr_err("Initial voltage set at %duV failed\n", level_uV);
 		return;
 	}
+
 	rc = regulator_enable(cpr->vreg_cx);
 	if (rc) {
 		pr_err("failed to enable %s, rc=%d\n", "vdd_cx", rc);
@@ -226,15 +246,13 @@
 	/* IRQ is already disabled */
 	rc = cpr_poll_result_done(cpr);
 	if (rc) {
-		pr_err("%s: Quot1: Exiting due to INT_DONE poll timeout\n",
-			__func__);
+		pr_err("Quot1: Exiting due to INT_DONE poll timeout\n");
 		return;
 	}
 
 	rc = cpr_poll_result(cpr);
 	if (rc) {
-		pr_err("%s: Quot1: Exiting due to BUSY poll timeout\n",
-			__func__);
+		pr_err("Quot1: Exiting due to BUSY poll timeout\n");
 		return;
 	}
 
@@ -242,14 +260,14 @@
 
 	/* Take second CPR measurement at a lower voltage to get QUOT2 */
 	level_uV -= 4 * cpr->vp->step_size;
-	pr_debug("tgt_volt_uV = %d\n", level_uV);
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+		"tgt_volt_uV = %d\n", level_uV);
 
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
 	/* Call the PMIC specific routine to set the voltage */
 	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
 	if (rc) {
-		pr_err("%s: Voltage set at %duV failed. %d\n",
-			__func__, level_uV, rc);
+		pr_err("Voltage set at %duV failed\n", level_uV);
 		return;
 	}
 
@@ -259,15 +277,13 @@
 	/* cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1); */
 	rc = cpr_poll_result_done(cpr);
 	if (rc) {
-		pr_err("%s: Quot2: Exiting due to INT_DONE poll timeout\n",
-			__func__);
+		pr_err("Quot2: Exiting due to INT_DONE poll timeout\n");
 		goto err_poll_result_done;
 	}
 	/* IRQ is already disabled */
 	rc = cpr_poll_result(cpr);
 	if (rc) {
-		pr_err("%s: Quot2: Exiting due to BUSY poll timeout\n",
-			__func__);
+		pr_err("Quot2: Exiting due to BUSY poll timeout\n");
 		goto err_poll_result;
 	}
 	quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
@@ -283,8 +299,8 @@
 			chip_data->step_quot > STEP_QUOT_MAX)
 		chip_data->step_quot = STEP_QUOT_MAX;
 
-	pr_info("%s: Step Quot is %d\n",
-			__func__, chip_data->step_quot);
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+		"Step Quot is %d\n", chip_data->step_quot);
 	/* Disable the cpr */
 	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
 
@@ -329,27 +345,31 @@
 static void
 cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
 {
-	int rc, set_volt_uV;
+	int set_volt_uV, rc;
 	struct msm_cpr_mode *chip_data;
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
 
-	/**
-	 * FIXME: Need to handle a potential race condition between
-	 * freq switch handler and CPR interrupt handler here
-	 */
 	/* Set New PMIC voltage */
+	msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+		"current Vmin=%d Vmax=%d\n", cpr->cur_Vmin, cpr->cur_Vmax);
 	set_volt_uV = (new_volt < cpr->cur_Vmax ? new_volt
 				: cpr->cur_Vmax);
-	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
-					set_volt_uV);
+
+	if (cpr->prev_volt_uV == set_volt_uV)
+		rc = regulator_sync_voltage(cpr->vreg_cx);
+	else
+		rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+							set_volt_uV);
 	if (rc) {
-		pr_err("%s: Voltage set at %duV failed. %d\n",
-			__func__, set_volt_uV, rc);
+		pr_err("Unable to set_voltage = %d, rc(%d)\n", set_volt_uV, rc);
 		cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
 		return;
 	}
-	pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+	msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+		"(railway_voltage: %d uV)\n", set_volt_uV);
+	cpr->prev_volt_uV = set_volt_uV;
 
 	cpr->max_volt_set = (set_volt_uV == cpr->cur_Vmax) ? 1 : 0;
 
@@ -371,27 +391,29 @@
 static void
 cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
 {
-	int rc, set_volt_uV;
+	int set_volt_uV, rc;
 	struct msm_cpr_mode *chip_data;
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
 
-	/**
-	 * FIXME: Need to handle a potential race condition between
-	 * freq switch handler and CPR interrupt handler here
-	 */
 	/* Set New PMIC volt */
 	set_volt_uV = (new_volt > cpr->cur_Vmin ? new_volt
 				: cpr->cur_Vmin);
-	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
-					set_volt_uV);
+
+	if (cpr->prev_volt_uV == set_volt_uV)
+		rc = regulator_sync_voltage(cpr->vreg_cx);
+	else
+		rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+							set_volt_uV);
 	if (rc) {
-		pr_err("%s: Voltage at %duV failed %d\n",
-			__func__, set_volt_uV, rc);
+		pr_err("Unable to set_voltage = %d, rc(%d)\n", set_volt_uV, rc);
 		cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
 		return;
 	}
-	pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+	msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+		"(railway_voltage: %d uV)\n", set_volt_uV);
+	cpr->prev_volt_uV = set_volt_uV;
 
 	cpr->max_volt_set = 0;
 
@@ -415,7 +437,8 @@
 					SW_AUTO_CONT_NACK_DN_EN_M,
 					SW_AUTO_CONT_NACK_DN_EN);
 			cpr_irq_set(cpr, DOWN_INT, 0);
-			pr_debug("%s: DOWN_INT disabled\n", __func__);
+			msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+					"DOWN_INT disabled\n");
 		}
 	}
 	/* Acknowledge the Recommendation */
@@ -429,9 +452,18 @@
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
 	error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
-	error_step &= 0xF;
 
+	msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+		"RBCPR_RESULT_0 17:6=%d\n", (cpr_read_reg(cpr,
+				RBCPR_RESULT_0) >> 6) & 0xFFF);
+	msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+		"RBCPR_RESULT_0 Busy_b19=%d\n", (cpr_read_reg(cpr,
+				RBCPR_RESULT_0) >> 19) & 0x1);
+
+	error_step &= 0xF;
 	curr_volt = regulator_get_voltage(cpr->vreg_cx);
+	msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+		"Current voltage=%d\n", curr_volt);
 
 	if (action == UP) {
 		/* Clear IRQ, ACK and return if Vdd already at Vmax */
@@ -447,15 +479,29 @@
 		 */
 		if (error_step < (cpr->config->up_threshold +
 					cpr->config->up_margin)) {
-			pr_debug("UP_INT error step too small to set\n");
+			msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+				"UP_INT error step too small to set\n");
 			cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
 			return;
 		}
 
+		/**
+		 * As per chip characterization recommendation, add a step
+		 * to up error steps to increase system stability
+		 */
+		error_step += 1;
+
 		/* Calculte new PMIC voltage */
 		new_volt = curr_volt + (error_step * cpr->vp->step_size);
-		pr_debug("UP_INT: new_volt: %d\n", new_volt);
-		pr_info("(UP Voltage recommended by CPR: %d uV)\n", new_volt);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"UP_INT: new_volt: %d, error_step=%d\n",
+					new_volt, error_step);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"Current RBCPR_GCNT_TARGET(%d): = 0x%x\n",
+			cpr->curr_osc, readl_relaxed(cpr->base +
+			RBCPR_GCNT_TARGET(cpr->curr_osc)) & TARGET_M);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"(UP Voltage recommended by CPR: %d uV)\n", new_volt);
 		cpr_up_event_handler(cpr, new_volt);
 
 	} else if (action == DOWN) {
@@ -465,15 +511,35 @@
 		 */
 		if (error_step < (cpr->config->dn_threshold +
 					cpr->config->dn_margin)) {
-			pr_debug("DOWN_INT error_step too small to set\n");
+			msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+				"DOWN_INT error_step=%d is too small to set\n",
+								error_step);
 			cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
 			return;
 		}
 
+		/**
+		 * As per chip characterization recommendation, deduct 2 steps
+		 * from down error steps to decrease chances of getting closer
+		 * to the system level Vmin, thereby improving stability
+		 */
+		error_step -= 2;
+
+		/* Keep down step upto two per interrupt to avoid any spike */
+		if (error_step > 2)
+			error_step = 2;
+
 		/* Calculte new PMIC voltage */
 		new_volt = curr_volt - (error_step * cpr->vp->step_size);
-		pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
-		pr_info("(DN Voltage recommended by CPR: %d uV)\n", new_volt);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"DOWN_INT: new_volt: %d, error_step=%d\n",
+			new_volt, error_step);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"Current RBCPR_GCNT_TARGET(%d): = 0x%x\n",
+			cpr->curr_osc, readl_relaxed(cpr->base +
+			RBCPR_GCNT_TARGET(cpr->curr_osc)) & TARGET_M);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"(DN Voltage recommended by CPR: %d uV)\n", new_volt);
 		cpr_dn_event_handler(cpr, new_volt);
 	}
 }
@@ -488,31 +554,36 @@
 
 	/* Following sequence of handling is as per each IRQ's priority */
 	if (reg_val & BIT(4)) {
-		pr_debug(" CPR:IRQ %d occured for UP Flag\n", irq);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"CPR:IRQ %d occured for UP Flag\n", irq);
 		cpr_set_vdd(cpr, UP);
 
 	} else if ((reg_val & BIT(2)) && !(ctl_reg & SW_AUTO_CONT_NACK_DN_EN)) {
-		pr_debug(" CPR:IRQ %d occured for Down Flag\n", irq);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"CPR:IRQ %d occured for Down Flag\n", irq);
 		cpr_set_vdd(cpr, DOWN);
 
 	} else if (reg_val & BIT(1)) {
-		pr_debug(" CPR:IRQ %d occured for Min Flag\n", irq);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"CPR:IRQ %d occured for Min Flag\n", irq);
 		cpr_irq_clr_and_nack(cpr, BIT(1) | BIT(0));
 
 	} else if (reg_val & BIT(5)) {
-		pr_debug(" CPR:IRQ %d occured for MAX Flag\n", irq);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"CPR:IRQ %d occured for MAX Flag\n", irq);
 		cpr_irq_clr_and_nack(cpr, BIT(5) | BIT(0));
 
 	} else if (reg_val & BIT(3)) {
 		/* SW_AUTO_CONT_ACK_EN is enabled */
-		pr_debug(" CPR:IRQ %d occured for Mid Flag\n", irq);
+		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+			"CPR:IRQ %d occured for Mid Flag\n", irq);
 	}
 	return IRQ_HANDLED;
 }
 
 static void cpr_config(struct msm_cpr *cpr)
 {
-	uint32_t delay_count, cnt = 0, rc, tmp_uV;
+	uint32_t delay_count, cnt = 0, rc;
 	struct msm_cpr_mode *chip_data;
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
@@ -543,11 +614,16 @@
 	 * for all the ring oscilators
 	 */
 	while (cnt < NUM_OSC) {
+		msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+			"Prog:cnt(%d) gcnt=0x%x quot=0x%x\n", cnt,
+			chip_data->ring_osc_data[cnt].gcnt,
+			chip_data->ring_osc_data[cnt].quot);
 		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
 				(GCNT_M | TARGET_M),
 				(chip_data->ring_osc_data[cnt].gcnt << 12 |
 				chip_data->ring_osc_data[cnt].quot));
-		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
+		msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+			"RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
 			readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
 		cnt++;
 	}
@@ -555,16 +631,11 @@
 	/* Configure the step quot */
 	cpr_2pt_kv_analysis(cpr, chip_data);
 
-	/**
-	 * Call the PMIC specific routine to set the voltage
-	 * Set with an extra step since it helps as per
-	 * characterization data.
-	 */
-	chip_data->calibrated_uV +=  cpr->vp->step_size;
-	tmp_uV = chip_data->calibrated_uV;
-	rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
+	/* Call the PMIC specific routine to set the voltage */
+	rc = regulator_set_voltage(cpr->vreg_cx, chip_data->calibrated_uV,
+					chip_data->calibrated_uV);
 	if (rc)
-		pr_err("%s: Voltage set failed %d\n", __func__, rc);
+		pr_err("Voltage set failed %d\n", rc);
 
 	/*
 	 * Program the Timer Register for delay between CPR measurements
@@ -575,6 +646,11 @@
 					cpr->config->delay_us);
 	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
 
+	/* Use Consecutive Down to avoid any interrupt due to spike */
+	cpr_write_reg(cpr, RBIF_TIMER_ADJUST, (0x2 << RBIF_CONS_DN_SHIFT));
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG, "RBIF_TIMER_ADJUST: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_TIMER_ADJUST));
+
 	/* Enable the Timer */
 	cpr_modify_reg(cpr, RBCPR_CTL, TIMER_M, ENABLE_TIMER);
 
@@ -593,19 +669,23 @@
 
 	switch (val) {
 	case CPUFREQ_PRECHANGE:
-		pr_debug("pre freq change notification to cpr\n");
-
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"pre freq change notification to cpr\n");
 		/* Disable Measurement to stop generation of CPR IRQs */
 		cpr_disable(cpr);
 		/* Disable routing of IRQ to App */
 		cpr_irq_set(cpr, INT_MASK & ~MID_INT, 0);
 		disable_irq(cpr->irq);
 		cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
-		pr_debug("RBCPR_CTL: 0x%x\n",
+
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBCPR_CTL: 0x%x\n",
 			readl_relaxed(cpr->base + RBCPR_CTL));
-		pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBIF_IRQ_STATUS: 0x%x\n",
 			cpr_read_reg(cpr, RBIF_IRQ_STATUS));
-		pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBIF_IRQ_EN(0): 0x%x\n",
 			cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
 
 		cpr->prev_mode = cpr->cpr_mode;
@@ -634,12 +714,15 @@
 						new_freq / 1000);
 		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cpr->curr_osc), TARGET_M,
 				quot);
-		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
 			readl_relaxed(cpr->base +
 					RBCPR_GCNT_TARGET(cpr->curr_osc)));
-		pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"new_freq: %d, quot_freq: %d, quot: %d\n",
 			freqs->new, new_freq, quot);
-		pr_info("%s: PVS Voltage setting is: %d\n", __func__,
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"PVS Voltage setting is: %d\n",
 			regulator_get_voltage(cpr->vreg_cx));
 
 		enable_irq(cpr->irq);
@@ -656,18 +739,28 @@
 		if (ctl_reg & SW_AUTO_CONT_NACK_DN_EN)
 			cpr_modify_reg(cpr, RBCPR_CTL,
 				 SW_AUTO_CONT_NACK_DN_EN_M, 0);
-		pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+		if (cpr->max_volt_set)
+			cpr->max_volt_set = 0;
+
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBIF_IRQ_EN(0): 0x%x\n",
 			cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
-		pr_debug("RBCPR_CTL: 0x%x\n",
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBCPR_CTL: 0x%x\n",
 			readl_relaxed(cpr->base + RBCPR_CTL));
-		pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+		msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+			"RBIF_IRQ_STATUS: 0x%x\n",
 			cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+
+		/* Clear all the interrupts */
+		cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
 		cpr_enable(cpr);
 		break;
 	default:
 		break;
 	}
-	return 0;
+	return NOTIFY_OK;
 }
 
 #ifdef CONFIG_PM
@@ -695,6 +788,9 @@
 	cpr_write_reg(cpr, RBCPR_CTL,
 		cpr_save_state.rbcpr_ctl);
 
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
 	enable_irq(cpr->irq);
 	cpr_enable(cpr);
 
@@ -711,6 +807,9 @@
 	cpr_disable(cpr);
 	disable_irq(cpr->irq);
 
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
 	cpr_save_state.rbif_timer_interval =
 		cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
 	cpr_save_state.rbif_int_en =
@@ -733,12 +832,18 @@
 
 void msm_cpr_pm_resume(void)
 {
+	if (!enable)
+		return;
+
 	msm_cpr_resume(&cpr_pdev->dev);
 }
 EXPORT_SYMBOL(msm_cpr_pm_resume);
 
 void msm_cpr_pm_suspend(void)
 {
+	if (!enable)
+		return;
+
 	msm_cpr_suspend(&cpr_pdev->dev);
 }
 EXPORT_SYMBOL(msm_cpr_pm_suspend);
@@ -746,14 +851,26 @@
 
 void msm_cpr_disable(void)
 {
-	struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+	struct msm_cpr *cpr;
+
+	if (!enable)
+		return;
+
+	cpr = platform_get_drvdata(cpr_pdev);
+
 	cpr_disable(cpr);
 }
 EXPORT_SYMBOL(msm_cpr_disable);
 
 void msm_cpr_enable(void)
 {
-	struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+	struct msm_cpr *cpr;
+
+	if (!enable)
+		return;
+
+	cpr = platform_get_drvdata(cpr_pdev);
+
 	cpr_enable(cpr);
 }
 EXPORT_SYMBOL(msm_cpr_enable);
@@ -772,12 +889,15 @@
 
 	if (!pdata) {
 		pr_err("CPR: Platform data is not available\n");
+		enable = false;
 		return -EIO;
 	}
 
 	cpr = devm_kzalloc(&pdev->dev, sizeof(struct msm_cpr), GFP_KERNEL);
-	if (!cpr)
+	if (!cpr) {
+		enable = false;
 		return -ENOMEM;
+	}
 
 	/* Initialize platform_data */
 	cpr->config = pdata;
@@ -820,7 +940,7 @@
 
 	cpr->vp = pdata->vp_data;
 
-	mutex_init(&cpr->cpr_mutex);
+	spin_lock_init(&cpr->cpr_lock);
 
 	/* Initialize the Voltage domain for CPR */
 	cpr->vreg_cx = regulator_get(&pdev->dev, "vddx_cx");
@@ -840,12 +960,15 @@
 	platform_set_drvdata(pdev, cpr);
 
 	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
-	pr_info("CPR Platform Data (upside_steps: %d) (downside_steps: %d) ",
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+		"CPR Platform Data (upside_steps: %d) (downside_steps: %d))",
 		cpr->config->up_threshold, cpr->config->dn_threshold);
-	pr_info("(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+		"(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
 		cpr->config->cpr_mode_data[NORMAL_MODE].calibrated_uV,
 		cpr->config->cpr_mode_data[TURBO_MODE].calibrated_uV);
-	pr_info("(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
+	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+		"(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
 		chip_data->ring_osc_data[chip_data->ring_osc].gcnt,
 		chip_data->ring_osc_data[chip_data->ring_osc].quot);
 
@@ -880,6 +1003,8 @@
 	cpufreq_register_notifier(&cpr->freq_transition,
 					CPUFREQ_TRANSITION_NOTIFIER);
 
+	pr_info("MSM CPR driver successfully registered!\n");
+
 	return res;
 
 err_reg_get:
@@ -887,6 +1012,7 @@
 err_ioremap:
 	iounmap(base);
 out:
+	enable = false;
 	return res;
 }
 
@@ -901,7 +1027,6 @@
 	regulator_put(cpr->vreg_cx);
 	free_irq(cpr->irq, cpr);
 	iounmap(cpr->base);
-	mutex_destroy(&cpr->cpr_mutex);
 	platform_set_drvdata(pdev, NULL);
 
 	return 0;
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index e690c63..005d9b1 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -72,6 +72,9 @@
 #define SW_AUTO_CONT_ACK_EN	BIT(5)
 #define SW_AUTO_CONT_NACK_DN_EN	BIT(6)
 
+/* Shift Values */
+#define RBIF_CONS_DN_SHIFT (0x4)
+
 /* Test values for RBCPR RUMI Testing */
 #define GNT_CNT			0xC0
 #define TARGET			0xEFF
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 0c158de..9601b7e 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,22 +39,34 @@
 };
 
 struct core_attribs {
+	struct kobj_attribute core_id;
 	struct kobj_attribute idle_enabled;
 	struct kobj_attribute freq_change_enabled;
 	struct kobj_attribute actual_freq;
 	struct kobj_attribute freq_change_us;
 
-	struct kobj_attribute max_time_us;
-
-	struct kobj_attribute slack_time_us;
-	struct kobj_attribute scale_slack_time;
-	struct kobj_attribute scale_slack_time_pct;
 	struct kobj_attribute disable_pc_threshold;
-	struct kobj_attribute em_window_size;
+	struct kobj_attribute em_win_size_min_us;
+	struct kobj_attribute em_win_size_max_us;
 	struct kobj_attribute em_max_util_pct;
-	struct kobj_attribute ss_window_size;
-	struct kobj_attribute ss_util_pct;
+	struct kobj_attribute group_id;
+	struct kobj_attribute max_freq_chg_time_us;
+	struct kobj_attribute slack_mode_dynamic;
+	struct kobj_attribute slack_time_min_us;
+	struct kobj_attribute slack_time_max_us;
+	struct kobj_attribute slack_weight_thresh_pct;
 	struct kobj_attribute ss_iobusy_conv;
+	struct kobj_attribute ss_win_size_min_us;
+	struct kobj_attribute ss_win_size_max_us;
+	struct kobj_attribute ss_util_pct;
+
+	struct kobj_attribute active_coeff_a;
+	struct kobj_attribute active_coeff_b;
+	struct kobj_attribute active_coeff_c;
+	struct kobj_attribute leakage_coeff_a;
+	struct kobj_attribute leakage_coeff_b;
+	struct kobj_attribute leakage_coeff_c;
+	struct kobj_attribute leakage_coeff_d;
 
 	struct attribute_group attrib_group;
 };
@@ -68,6 +80,7 @@
 	uint32_t max_time_us; /* core param */
 
 	struct msm_dcvs_algo_param algo_param;
+	struct msm_dcvs_energy_curve_coeffs coeffs;
 	struct msm_dcvs_idle *idle_driver;
 	struct msm_dcvs_freq *freq_driver;
 
@@ -78,12 +91,12 @@
 	struct task_struct *task;
 	struct core_attribs attrib;
 	uint32_t handle;
-	uint32_t group_id;
 	uint32_t freq_pending;
 	struct hrtimer timer;
 	int32_t timer_disabled;
 	/* track if kthread for change_freq is active */
 	int32_t change_freq_activated;
+	struct msm_dcvs_core_info *info;
 };
 
 static int msm_dcvs_debug;
@@ -365,6 +378,39 @@
 	return count; \
 }
 
+#define DCVS_ENERGY_PARAM(_name) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
+		struct kobj_attribute *attr, char *buf) \
+{ \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	return snprintf(buf, PAGE_SIZE, "%d\n", core->coeffs._name); \
+} \
+static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+	int ret = 0; \
+	int32_t val = 0; \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	mutex_lock(&core->lock); \
+	ret = kstrtoint(buf, 10, &val); \
+	if (ret) { \
+		__err("Invalid input %s for %s\n", buf, __stringify(_name));\
+	} else { \
+		int32_t old_val = core->coeffs._name; \
+		core->coeffs._name = val; \
+		ret = msm_dcvs_scm_set_power_params(core->handle, \
+			&core->info->power_param, &core->info->freq_tbl[0], \
+				&core->coeffs); \
+		if (ret) { \
+			core->coeffs._name = old_val; \
+			__err("Error(%d) in setting %d for coeffs param %s\n",\
+					ret, val, __stringify(_name)); \
+		} \
+	} \
+	mutex_unlock(&core->lock); \
+	return count; \
+}
+
 #define DCVS_RO_ATTRIB(i, _name) \
 	core->attrib._name.attr.name = __stringify(_name); \
 	core->attrib._name.attr.mode = S_IRUGO; \
@@ -383,27 +429,40 @@
  * Function declarations for different attributes.
  * Gets used when setting the attribute show and store parameters.
  */
+DCVS_PARAM_SHOW(core_id, core->handle)
 DCVS_PARAM_SHOW(idle_enabled, (core->idle_driver != NULL))
 DCVS_PARAM_SHOW(freq_change_enabled, (core->freq_driver != NULL))
 DCVS_PARAM_SHOW(actual_freq, (core->actual_freq))
 DCVS_PARAM_SHOW(freq_change_us, (core->freq_change_us))
-DCVS_PARAM_SHOW(max_time_us, (core->max_time_us))
 
-DCVS_ALGO_PARAM(slack_time_us)
-DCVS_ALGO_PARAM(scale_slack_time)
-DCVS_ALGO_PARAM(scale_slack_time_pct)
 DCVS_ALGO_PARAM(disable_pc_threshold)
-DCVS_ALGO_PARAM(em_window_size)
+DCVS_ALGO_PARAM(em_win_size_min_us)
+DCVS_ALGO_PARAM(em_win_size_max_us)
 DCVS_ALGO_PARAM(em_max_util_pct)
-DCVS_ALGO_PARAM(ss_window_size)
-DCVS_ALGO_PARAM(ss_util_pct)
+DCVS_ALGO_PARAM(group_id)
+DCVS_ALGO_PARAM(max_freq_chg_time_us)
+DCVS_ALGO_PARAM(slack_mode_dynamic)
+DCVS_ALGO_PARAM(slack_time_min_us)
+DCVS_ALGO_PARAM(slack_time_max_us)
+DCVS_ALGO_PARAM(slack_weight_thresh_pct)
 DCVS_ALGO_PARAM(ss_iobusy_conv)
+DCVS_ALGO_PARAM(ss_win_size_min_us)
+DCVS_ALGO_PARAM(ss_win_size_max_us)
+DCVS_ALGO_PARAM(ss_util_pct)
+
+DCVS_ENERGY_PARAM(active_coeff_a)
+DCVS_ENERGY_PARAM(active_coeff_b)
+DCVS_ENERGY_PARAM(active_coeff_c)
+DCVS_ENERGY_PARAM(leakage_coeff_a)
+DCVS_ENERGY_PARAM(leakage_coeff_b)
+DCVS_ENERGY_PARAM(leakage_coeff_c)
+DCVS_ENERGY_PARAM(leakage_coeff_d)
 
 static int msm_dcvs_setup_core_sysfs(struct dcvs_core *core)
 {
 	int ret = 0;
 	struct kobject *core_kobj = NULL;
-	const int attr_count = 15;
+	const int attr_count = 27;
 
 	BUG_ON(!cores_kobj);
 
@@ -415,23 +474,37 @@
 		goto done;
 	}
 
-	DCVS_RO_ATTRIB(0, idle_enabled);
-	DCVS_RO_ATTRIB(1, freq_change_enabled);
-	DCVS_RO_ATTRIB(2, actual_freq);
-	DCVS_RO_ATTRIB(3, freq_change_us);
-	DCVS_RO_ATTRIB(4, max_time_us);
 
-	DCVS_RW_ATTRIB(5, slack_time_us);
-	DCVS_RW_ATTRIB(6, scale_slack_time);
-	DCVS_RW_ATTRIB(7, scale_slack_time_pct);
-	DCVS_RW_ATTRIB(8, disable_pc_threshold);
-	DCVS_RW_ATTRIB(9, em_window_size);
-	DCVS_RW_ATTRIB(10, em_max_util_pct);
-	DCVS_RW_ATTRIB(11, ss_window_size);
-	DCVS_RW_ATTRIB(12, ss_util_pct);
-	DCVS_RW_ATTRIB(13, ss_iobusy_conv);
+	DCVS_RO_ATTRIB(0, core_id);
+	DCVS_RO_ATTRIB(1, idle_enabled);
+	DCVS_RO_ATTRIB(2, freq_change_enabled);
+	DCVS_RO_ATTRIB(3, actual_freq);
+	DCVS_RO_ATTRIB(4, freq_change_us);
 
-	core->attrib.attrib_group.attrs[14] = NULL;
+	DCVS_RW_ATTRIB(5, disable_pc_threshold);
+	DCVS_RW_ATTRIB(6, em_win_size_min_us);
+	DCVS_RW_ATTRIB(7, em_win_size_max_us);
+	DCVS_RW_ATTRIB(8, em_max_util_pct);
+	DCVS_RW_ATTRIB(9, group_id);
+	DCVS_RW_ATTRIB(10, max_freq_chg_time_us);
+	DCVS_RW_ATTRIB(11, slack_mode_dynamic);
+	DCVS_RW_ATTRIB(12, slack_time_min_us);
+	DCVS_RW_ATTRIB(13, slack_time_max_us);
+	DCVS_RW_ATTRIB(14, slack_weight_thresh_pct);
+	DCVS_RW_ATTRIB(15, ss_iobusy_conv);
+	DCVS_RW_ATTRIB(16, ss_win_size_min_us);
+	DCVS_RW_ATTRIB(17, ss_win_size_max_us);
+	DCVS_RW_ATTRIB(18, ss_util_pct);
+
+	DCVS_RW_ATTRIB(19, active_coeff_a);
+	DCVS_RW_ATTRIB(20, active_coeff_b);
+	DCVS_RW_ATTRIB(21, active_coeff_c);
+	DCVS_RW_ATTRIB(22, leakage_coeff_a);
+	DCVS_RW_ATTRIB(23, leakage_coeff_b);
+	DCVS_RW_ATTRIB(24, leakage_coeff_c);
+	DCVS_RW_ATTRIB(25, leakage_coeff_d);
+
+	core->attrib.attrib_group.attrs[26] = NULL;
 
 	core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
 	if (!core_kobj) {
@@ -497,11 +570,13 @@
 	return core;
 }
 
-int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
+int msm_dcvs_register_core(const char *core_name,
 		struct msm_dcvs_core_info *info)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
+	uint32_t ret1;
+	uint32_t ret2;
 
 	if (!core_name || !core_name[0])
 		return ret;
@@ -511,25 +586,15 @@
 		return ret;
 
 	mutex_lock(&core->lock);
-	if (group_id) {
-		/**
-		 * Create a group for cores, if this core is part of a group
-		 * if the group_id is 0, the core is not part of a group.
-		 * If the group_id already exits, it will through an error
-		 * which we will ignore.
-		 */
-		ret = msm_dcvs_scm_create_group(group_id);
-		if (ret == -ENOMEM)
-			goto bail;
-	}
-	core->group_id = group_id;
 
-	core->max_time_us = info->core_param.max_time_us;
+	core->info = info;
 	memcpy(&core->algo_param, &info->algo_param,
 			sizeof(struct msm_dcvs_algo_param));
 
-	ret = msm_dcvs_scm_register_core(core->handle, group_id,
-			&info->core_param, info->freq_tbl);
+	memcpy(&core->coeffs, &info->energy_coeffs,
+			sizeof(struct msm_dcvs_energy_curve_coeffs));
+
+	ret = msm_dcvs_scm_register_core(core->handle, &info->core_param);
 	if (ret)
 		goto bail;
 
@@ -537,6 +602,16 @@
 	if (ret)
 		goto bail;
 
+	ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
+				&info->freq_tbl[0], &core->coeffs);
+	if (ret)
+		goto bail;
+
+	ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CORE_ONLINE,
+				core->actual_freq, 0, &ret1, &ret2);
+	if (ret)
+		goto bail;
+
 	ret = msm_dcvs_setup_core_sysfs(core);
 	if (ret) {
 		__err("Unable to setup core %s sysfs\n", core->core_name);
@@ -582,7 +657,7 @@
 	if (core->idle_driver) {
 		core->actual_freq = core->freq_driver->get_frequency(drv);
 		/* Notify TZ to start receiving idle info for the core */
-		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 1,
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
 					   &ret1, &ret2);
 		core->idle_driver->enable(core->idle_driver,
 				MSM_DCVS_ENABLE_IDLE_PULSE);
@@ -615,7 +690,7 @@
 		core->idle_driver->enable(core->idle_driver,
 				MSM_DCVS_DISABLE_IDLE_PULSE);
 		/* Notify TZ to stop receiving idle info for the core */
-		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 0,
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 0,
 					   &ret1, &ret2);
 		hrtimer_cancel(&core->timer);
 		core->idle_driver->enable(core->idle_driver,
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
index 6095e0813..df6c44f 100644
--- a/arch/arm/mach-msm/msm_dcvs_scm.c
+++ b/arch/arm/mach-msm/msm_dcvs_scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,17 +21,15 @@
 #include <mach/scm.h>
 #include <mach/msm_dcvs_scm.h>
 
-#define DCVS_CMD_CREATE_GROUP		1
 #define DCVS_CMD_REGISTER_CORE		2
 #define DCVS_CMD_SET_ALGO_PARAM		3
 #define DCVS_CMD_EVENT			4
 #define DCVS_CMD_INIT			5
+#define DCVS_CMD_SET_POWER_PARAM	6
 
 struct scm_register_core {
 	uint32_t core_id;
-	uint32_t group_id;
 	phys_addr_t core_param_phy;
-	phys_addr_t freq_phy;
 };
 
 struct scm_algo {
@@ -44,6 +42,21 @@
 	uint32_t size;
 };
 
+struct scm_pwr_param {
+	uint32_t	core_id;
+	phys_addr_t	pwr_param_phy;
+	phys_addr_t	freq_phy;
+	phys_addr_t	coeffs_phy;
+};
+
+struct msm_algo_param {
+	enum msm_dcvs_algo_param_type		type;
+	union {
+		struct msm_dcvs_algo_param	dcvs_param;
+		struct msm_mpd_algo_param	mpd_param;
+	} u;
+};
+
 int msm_dcvs_scm_init(size_t size)
 {
 	int ret = 0;
@@ -69,49 +82,25 @@
 }
 EXPORT_SYMBOL(msm_dcvs_scm_init);
 
-int msm_dcvs_scm_create_group(uint32_t id)
-{
-	int ret = 0;
-
-	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_CREATE_GROUP,
-			&id, sizeof(uint32_t), NULL, 0);
-
-	return ret;
-}
-EXPORT_SYMBOL(msm_dcvs_scm_create_group);
-
-int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
-		struct msm_dcvs_core_param *param,
-		struct msm_dcvs_freq_entry *freq)
+int msm_dcvs_scm_register_core(uint32_t core_id,
+		struct msm_dcvs_core_param *param)
 {
 	int ret = 0;
 	struct scm_register_core reg_data;
 	struct msm_dcvs_core_param *p = NULL;
-	struct msm_dcvs_freq_entry *f = NULL;
 
 	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_core_param)), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
-	f = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry) *
-				param->num_freq), GFP_KERNEL);
-	if (!f) {
-		kfree(p);
-		return -ENOMEM;
-	}
-
 	memcpy(p, param, sizeof(struct msm_dcvs_core_param));
-	memcpy(f, freq, sizeof(struct msm_dcvs_freq_entry) * param->num_freq);
 
 	reg_data.core_id = core_id;
-	reg_data.group_id = group_id;
 	reg_data.core_param_phy = virt_to_phys(p);
-	reg_data.freq_phy = virt_to_phys(f);
 
 	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
 			&reg_data, sizeof(reg_data), NULL, 0);
 
-	kfree(f);
 	kfree(p);
 
 	return ret;
@@ -123,13 +112,14 @@
 {
 	int ret = 0;
 	struct scm_algo algo;
-	struct msm_dcvs_algo_param *p = NULL;
+	struct msm_algo_param *p = NULL;
 
-	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_algo_param)), GFP_KERNEL);
+	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_algo_param)), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
-	memcpy(p, param, sizeof(struct msm_dcvs_algo_param));
+	p->type = MSM_DCVS_ALGO_DCVS_PARAM;
+	memcpy(&p->u.dcvs_param, param, sizeof(struct msm_dcvs_algo_param));
 
 	algo.core_id = core_id;
 	algo.algo_phy = virt_to_phys(p);
@@ -143,6 +133,85 @@
 }
 EXPORT_SYMBOL(msm_dcvs_scm_set_algo_params);
 
+int msm_mpd_scm_set_algo_params(struct msm_mpd_algo_param *param)
+{
+	int ret = 0;
+	struct scm_algo algo;
+	struct msm_algo_param *p = NULL;
+
+	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_algo_param)), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	p->type = MSM_DCVS_ALGO_MPD_PARAM;
+	memcpy(&p->u.mpd_param, param, sizeof(struct msm_mpd_algo_param));
+
+	algo.core_id = 0;
+	algo.algo_phy = virt_to_phys(p);
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
+			&algo, sizeof(algo), NULL, 0);
+
+	kfree(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_mpd_scm_set_algo_params);
+
+int msm_dcvs_scm_set_power_params(uint32_t core_id,
+		struct msm_dcvs_power_params *pwr_param,
+		struct msm_dcvs_freq_entry *freq_entry,
+		struct msm_dcvs_energy_curve_coeffs *coeffs)
+{
+	int ret = 0;
+	struct scm_pwr_param pwr;
+	struct msm_dcvs_power_params *pwrt = NULL;
+	struct msm_dcvs_freq_entry *freqt = NULL;
+	struct msm_dcvs_energy_curve_coeffs *coefft = NULL;
+
+	pwrt = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_power_params)),
+			GFP_KERNEL);
+	if (!pwrt)
+		return -ENOMEM;
+
+	freqt = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry)
+				* pwr_param->num_freq),
+			GFP_KERNEL);
+	if (!freqt) {
+		kfree(pwrt);
+		return -ENOMEM;
+	}
+
+	coefft = kzalloc(PAGE_ALIGN(
+				sizeof(struct msm_dcvs_energy_curve_coeffs)),
+				GFP_KERNEL);
+	if (!coefft) {
+		kfree(pwrt);
+		kfree(freqt);
+		return -ENOMEM;
+	}
+
+	memcpy(pwrt, pwr_param, sizeof(struct msm_dcvs_power_params));
+	memcpy(freqt, freq_entry,
+			sizeof(struct msm_dcvs_freq_entry)*pwr_param->num_freq);
+	memcpy(coefft, coeffs, sizeof(struct msm_dcvs_energy_curve_coeffs));
+
+	pwr.core_id = core_id;
+	pwr.pwr_param_phy = virt_to_phys(pwrt);
+	pwr.freq_phy = virt_to_phys(freqt);
+	pwr.coeffs_phy = virt_to_phys(coefft);
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_POWER_PARAM,
+			&pwr, sizeof(pwr), NULL, 0);
+
+	kfree(pwrt);
+	kfree(freqt);
+	kfree(coefft);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_set_power_params);
+
 int msm_dcvs_scm_event(uint32_t core_id,
 		enum msm_dcvs_scm_event event_id,
 		uint32_t param0, uint32_t param1,
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 6dde576..c39829b 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -45,7 +45,7 @@
 #include "timer.h"
 
 #define DRV_NAME	"msm_dsps"
-#define DRV_VERSION	"4.02"
+#define DRV_VERSION	"4.03"
 
 
 #define PPSS_TIMER0_32KHZ_REG	0x1004
@@ -771,6 +771,11 @@
 {
 	pr_debug("%s\n", __func__);
 	disable_irq_nosync(drv->wdog_irq);
+	if (drv->pdata->ppss_wdog_unmasked_int_en_reg) {
+		writel_relaxed(0, (drv->ppss_base+
+			drv->pdata->ppss_wdog_unmasked_int_en_reg));
+		mb(); /* Make sure wdog is disabled before shutting down */
+	}
 	pil_force_shutdown(drv->pdata->pil_name);
 	dsps_power_off_handler();
 	return 0;
@@ -799,6 +804,7 @@
 static void dsps_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
+	disable_irq_nosync(drv->wdog_irq);
 	dsps_crash_shutdown_g = 1;
 	smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
 }
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
new file mode 100644
index 0000000..056e4eb
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -0,0 +1,707 @@
+ /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)     "mpd %s: " fmt, __func__
+
+#include <linux/cpumask.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <linux/stringify.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/sched.h>
+#include <linux/rq_stats.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_dcvs_scm.h>
+
+#define DEFAULT_RQ_AVG_POLL_MS    (1)
+
+struct mpd_attrib {
+	struct kobj_attribute	enabled;
+	struct kobj_attribute	rq_avg_poll_ms;
+	struct kobj_attribute iowait_threshold_pct;
+
+	struct kobj_attribute	em_win_size_min_us;
+	struct kobj_attribute	em_win_size_max_us;
+	struct kobj_attribute	em_max_util_pct;
+	struct kobj_attribute	mp_em_rounding_point_min;
+	struct kobj_attribute	mp_em_rounding_point_max;
+	struct kobj_attribute	online_util_pct_min;
+	struct kobj_attribute	online_util_pct_max;
+	struct kobj_attribute	slack_time_min_us;
+	struct kobj_attribute	slack_time_max_us;
+	struct kobj_attribute	hp_up_max_ms;
+	struct kobj_attribute	hp_up_ms;
+	struct kobj_attribute	hp_up_count;
+	struct kobj_attribute	hp_dw_max_ms;
+	struct kobj_attribute	hp_dw_ms;
+	struct kobj_attribute	hp_dw_count;
+	struct attribute_group	attrib_group;
+};
+
+struct msm_mpd_scm_data {
+	enum msm_dcvs_scm_event event;
+	int			nr;
+};
+
+struct mpdecision {
+	uint32_t			enabled;
+	atomic_t			algo_cpu_mask;
+	uint32_t			rq_avg_poll_ms;
+	uint32_t			iowait_threshold_pct;
+	ktime_t				next_update;
+	uint32_t			slack_us;
+	struct msm_mpd_algo_param	mp_param;
+	struct mpd_attrib		attrib;
+	struct mutex			lock;
+	struct task_struct		*task;
+	struct task_struct		*hptask;
+	struct hrtimer			slack_timer;
+	struct msm_mpd_scm_data		data;
+	int				hpupdate;
+	wait_queue_head_t		wait_q;
+	wait_queue_head_t		wait_hpq;
+};
+
+struct hp_latency {
+	int hp_up_max_ms;
+	int hp_up_ms;
+	int hp_up_count;
+	int hp_dw_max_ms;
+	int hp_dw_ms;
+	int hp_dw_count;
+};
+
+static DEFINE_PER_CPU(struct hrtimer, rq_avg_poll_timer);
+static DEFINE_SPINLOCK(rq_avg_lock);
+
+enum {
+	MSM_MPD_DEBUG_NOTIFIER = BIT(0),
+	MSM_MPD_CORE_STATUS = BIT(1),
+	MSM_MPD_SLACK_TIMER = BIT(2),
+};
+
+enum {
+	HPUPDATE_WAITING = 0, /* we are waiting for cpumask update */
+	HPUPDATE_SCHEDULED = 1, /* we are in the process of hotplugging */
+	HPUPDATE_IN_PROGRESS = 2, /* we are in the process of hotplugging */
+};
+
+static int msm_mpd_enabled = 1;
+module_param_named(enabled, msm_mpd_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static struct dentry *debugfs_base;
+static struct mpdecision msm_mpd;
+
+static struct hp_latency hp_latencies;
+
+static unsigned long last_nr;
+static int num_present_hundreds;
+
+#define RQ_AVG_INSIGNIFICANT_BITS	3
+static bool ok_to_update_tz(int nr, int last_nr)
+{
+	/*
+	 * Exclude unnecessary TZ reports if run queue haven't changed much from
+	 * the last reported value. The left shift by INSIGNIFICANT_BITS is to
+	 * filter out small changes in the run queue average which won't cause
+	 * a online cpu mask change. Also if the cpu online count does not match
+	 * the count requested by TZ and we are not in the process of bringing
+	 * cpus online as indicated by a HPUPDATE_IN_PROGRESS in msm_mpd.hpdata
+	 */
+	return
+	(((nr >> RQ_AVG_INSIGNIFICANT_BITS)
+				!= (last_nr >> RQ_AVG_INSIGNIFICANT_BITS))
+	|| ((hweight32(atomic_read(&msm_mpd.algo_cpu_mask))
+				!= num_online_cpus())
+		&& (msm_mpd.hpupdate != HPUPDATE_IN_PROGRESS)));
+}
+
+static enum hrtimer_restart msm_mpd_rq_avg_poll_timer(struct hrtimer *timer)
+{
+	int nr, nr_iowait;
+	ktime_t curr_time = ktime_get();
+	unsigned long flags;
+	int cpu = smp_processor_id();
+	enum hrtimer_restart restart = HRTIMER_RESTART;
+
+	spin_lock_irqsave(&rq_avg_lock, flags);
+	/* If running on the wrong cpu, don't restart */
+	if (&per_cpu(rq_avg_poll_timer, cpu) != timer)
+		restart = HRTIMER_NORESTART;
+
+	if (ktime_to_ns(ktime_sub(curr_time, msm_mpd.next_update)) < 0)
+		goto out;
+
+	msm_mpd.next_update = ktime_add_ns(curr_time,
+			(msm_mpd.rq_avg_poll_ms * NSEC_PER_MSEC));
+
+	sched_get_nr_running_avg(&nr, &nr_iowait);
+
+	if ((nr_iowait >= msm_mpd.iowait_threshold_pct) && (nr < last_nr))
+		nr = last_nr;
+
+	if (nr > num_present_hundreds)
+		nr = num_present_hundreds;
+
+	if (ok_to_update_tz(nr, last_nr)) {
+		hrtimer_try_to_cancel(&msm_mpd.slack_timer);
+		msm_mpd.data.nr = nr;
+		msm_mpd.data.event = MSM_DCVS_SCM_RUNQ_UPDATE;
+		wake_up(&msm_mpd.wait_q);
+		last_nr = nr;
+	}
+
+out:
+	hrtimer_set_expires(timer, msm_mpd.next_update);
+	spin_unlock_irqrestore(&rq_avg_lock, flags);
+	/* set next expiration */
+	return restart;
+}
+
+static void bring_up_cpu(int cpu)
+{
+	int cpu_action_time_ms;
+	int time_taken_ms;
+	int ret, ret1, ret2;
+
+	cpu_action_time_ms = ktime_to_ms(ktime_get());
+	ret = cpu_up(cpu);
+	if (ret) {
+		pr_debug("Error %d online core %d\n", ret, cpu);
+	} else {
+		time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
+		if (time_taken_ms > hp_latencies.hp_up_max_ms)
+			hp_latencies.hp_up_max_ms = time_taken_ms;
+		if (time_taken_ms > 5)
+			pr_warn("cpu_up for cpu%d exceeded 5ms (%d)\n",
+					cpu, time_taken_ms);
+		hp_latencies.hp_up_ms += time_taken_ms;
+		hp_latencies.hp_up_count++;
+		ret = msm_dcvs_scm_event(
+				CPU_OFFSET + cpu,
+				MSM_DCVS_SCM_CORE_ONLINE,
+				cpufreq_get(cpu),
+				(uint32_t) time_taken_ms * USEC_PER_MSEC,
+				&ret1, &ret2);
+		if (ret)
+			pr_err("Error sending hotplug scm event err=%d\n", ret);
+	}
+}
+
+static void bring_down_cpu(int cpu)
+{
+	int cpu_action_time_ms;
+	int time_taken_ms;
+	int ret, ret1, ret2;
+
+	BUG_ON(cpu == 0);
+	cpu_action_time_ms = ktime_to_ms(ktime_get());
+	ret = cpu_down(cpu);
+	if (ret) {
+		pr_debug("Error %d offline" "core %d\n", ret, cpu);
+	} else {
+		time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
+		if (time_taken_ms > hp_latencies.hp_dw_max_ms)
+			hp_latencies.hp_dw_max_ms = time_taken_ms;
+		if (time_taken_ms > 5)
+			pr_warn("cpu_down for cpu%d exceeded 5ms (%d)\n",
+						cpu, time_taken_ms);
+		hp_latencies.hp_dw_ms += time_taken_ms;
+		hp_latencies.hp_dw_count++;
+		ret = msm_dcvs_scm_event(
+				CPU_OFFSET + cpu,
+				MSM_DCVS_SCM_CORE_OFFLINE,
+				(uint32_t) time_taken_ms * USEC_PER_MSEC,
+				0,
+				&ret1, &ret2);
+		if (ret)
+			pr_err("Error sending hotplug scm event err=%d\n", ret);
+	}
+}
+
+static int __ref msm_mpd_update_scm(enum msm_dcvs_scm_event event, int nr)
+{
+	int ret = 0;
+	uint32_t req_cpu_mask = 0;
+	uint32_t slack_us = 0;
+	uint32_t param0 = 0;
+
+	if (event == MSM_DCVS_SCM_RUNQ_UPDATE)
+		param0 = nr;
+
+	ret = msm_dcvs_scm_event(0, event, param0, 0,
+				 &req_cpu_mask, &slack_us);
+
+	if (ret) {
+		pr_err("Error (%d) sending event %d, param %d\n", ret, event,
+				param0);
+		return ret;
+	}
+
+	msm_mpd.slack_us = slack_us;
+	atomic_set(&msm_mpd.algo_cpu_mask, req_cpu_mask);
+	msm_mpd.hpupdate = HPUPDATE_SCHEDULED;
+	wake_up(&msm_mpd.wait_hpq);
+
+	/* Start MP Decision slack timer */
+	if (slack_us) {
+		hrtimer_cancel(&msm_mpd.slack_timer);
+		ret = hrtimer_start(&msm_mpd.slack_timer,
+				ktime_set(0, slack_us * NSEC_PER_USEC),
+				HRTIMER_MODE_REL_PINNED);
+		if (ret)
+			pr_err("Failed to register slack timer (%d) %d\n",
+					slack_us, ret);
+	}
+
+	return ret;
+}
+
+static enum hrtimer_restart msm_mpd_slack_timer(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rq_avg_lock, flags);
+	if (msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE)
+		goto out;
+
+	msm_mpd.data.nr = 0;
+	msm_mpd.data.event = MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED;
+	wake_up(&msm_mpd.wait_q);
+out:
+	spin_unlock_irqrestore(&rq_avg_lock, flags);
+	return HRTIMER_NORESTART;
+}
+
+static int msm_mpd_idle_notifier(struct notifier_block *self,
+				 unsigned long cmd, void *v)
+{
+	int cpu = smp_processor_id();
+	unsigned long flags;
+
+	switch (cmd) {
+	case CPU_PM_EXIT:
+		spin_lock_irqsave(&rq_avg_lock, flags);
+		hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
+			      msm_mpd.next_update,
+			      HRTIMER_MODE_ABS_PINNED);
+		spin_unlock_irqrestore(&rq_avg_lock, flags);
+		break;
+	case CPU_PM_ENTER:
+		hrtimer_cancel(&per_cpu(rq_avg_poll_timer, cpu));
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int msm_mpd_hotplug_notifier(struct notifier_block *self,
+				    unsigned long action, void *hcpu)
+{
+	int cpu = (int)hcpu;
+	unsigned long flags;
+
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		spin_lock_irqsave(&rq_avg_lock, flags);
+		hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
+			      msm_mpd.next_update,
+			      HRTIMER_MODE_ABS_PINNED);
+		spin_unlock_irqrestore(&rq_avg_lock, flags);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block msm_mpd_idle_nb = {
+	.notifier_call = msm_mpd_idle_notifier,
+};
+
+static struct notifier_block msm_mpd_hotplug_nb = {
+	.notifier_call = msm_mpd_hotplug_notifier,
+};
+
+static int __cpuinit msm_mpd_do_hotplug(void *data)
+{
+	int *event = (int *)data;
+	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
+	int cpu;
+
+	sched_setscheduler(current, SCHED_FIFO, &param);
+
+	while (1) {
+		wait_event(msm_mpd.wait_hpq, *event || kthread_should_stop());
+		if (kthread_should_stop())
+			break;
+
+		msm_mpd.hpupdate = HPUPDATE_IN_PROGRESS;
+		/*
+		 * Bring online any offline cores, then offline any online
+		 * cores.  Whenever a core is off/onlined restart the procedure
+		 * in case a new core is desired to be brought online in the
+		 * mean time.
+		 */
+restart:
+		for_each_possible_cpu(cpu) {
+			if ((atomic_read(&msm_mpd.algo_cpu_mask) & (1 << cpu))
+				&& !cpu_online(cpu)) {
+				bring_up_cpu(cpu);
+				if (cpu_online(cpu))
+					goto restart;
+			}
+		}
+
+		for_each_possible_cpu(cpu) {
+			if (!(atomic_read(&msm_mpd.algo_cpu_mask) & (1 << cpu))
+				&& cpu_online(cpu)) {
+				bring_down_cpu(cpu);
+				if (!cpu_online(cpu))
+					goto restart;
+			}
+		}
+		msm_mpd.hpupdate = HPUPDATE_WAITING;
+	}
+
+	return 0;
+}
+
+static int msm_mpd_do_update_scm(void *data)
+{
+	struct msm_mpd_scm_data *scm_data = (struct msm_mpd_scm_data *)data;
+	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
+	unsigned long flags;
+	enum msm_dcvs_scm_event event;
+	int nr;
+
+	sched_setscheduler(current, SCHED_FIFO, &param);
+
+	while (1) {
+		wait_event(msm_mpd.wait_q,
+			msm_mpd.data.event == MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED
+			|| msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE
+			|| kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		spin_lock_irqsave(&rq_avg_lock, flags);
+		event = scm_data->event;
+		nr = scm_data->nr;
+		scm_data->event = 0;
+		scm_data->nr = 0;
+		spin_unlock_irqrestore(&rq_avg_lock, flags);
+
+		msm_mpd_update_scm(event, nr);
+	}
+	return 0;
+}
+
+static int __ref msm_mpd_set_enabled(uint32_t enable)
+{
+	int ret = 0;
+	int ret0 = 0;
+	int ret1 = 0;
+	int cpu;
+	static uint32_t last_enable;
+
+	enable = (enable > 0) ? 1 : 0;
+	if (last_enable == enable)
+		return ret;
+
+	if (enable) {
+		ret = msm_mpd_scm_set_algo_params(&msm_mpd.mp_param);
+		if (ret) {
+			pr_err("Error(%d): msm_mpd_scm_set_algo_params failed\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = msm_dcvs_scm_event(0, MSM_DCVS_SCM_MPD_ENABLE, enable, 0,
+			&ret0, &ret1);
+	if (ret) {
+		pr_err("Error(%d) %s MP Decision\n",
+				ret, (enable ? "enabling" : "disabling"));
+	} else {
+		last_enable = enable;
+		last_nr = 0;
+	}
+	if (enable) {
+		msm_mpd.next_update = ktime_add_ns(ktime_get(),
+				(msm_mpd.rq_avg_poll_ms * NSEC_PER_MSEC));
+		msm_mpd.task = kthread_run(msm_mpd_do_update_scm,
+					      &msm_mpd.data, "msm_mpdecision");
+		if (IS_ERR(msm_mpd.task))
+			return -EFAULT;
+
+		msm_mpd.hptask = kthread_run(msm_mpd_do_hotplug,
+						&msm_mpd.hpupdate, "msm_hp");
+		if (IS_ERR(msm_mpd.hptask))
+			return -EFAULT;
+
+		for_each_online_cpu(cpu)
+			hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
+				      msm_mpd.next_update,
+				      HRTIMER_MODE_ABS_PINNED);
+		cpu_pm_register_notifier(&msm_mpd_idle_nb);
+		register_cpu_notifier(&msm_mpd_hotplug_nb);
+		msm_mpd.enabled = 1;
+	} else {
+		for_each_online_cpu(cpu)
+			hrtimer_cancel(&per_cpu(rq_avg_poll_timer, cpu));
+		kthread_stop(msm_mpd.hptask);
+		kthread_stop(msm_mpd.task);
+		cpu_pm_unregister_notifier(&msm_mpd_idle_nb);
+		unregister_cpu_notifier(&msm_mpd_hotplug_nb);
+		msm_mpd.enabled = 0;
+	}
+
+	return ret;
+}
+
+static int msm_mpd_set_rq_avg_poll_ms(uint32_t val)
+{
+	/*
+	 * No need to do anything. Just let the timer set its own next poll
+	 * interval when it next fires.
+	 */
+	msm_mpd.rq_avg_poll_ms = val;
+	return 0;
+}
+
+static int msm_mpd_set_iowait_threshold_pct(uint32_t val)
+{
+	/*
+	 * No need to do anything. Just let the timer set its own next poll
+	 * interval when it next fires.
+	 */
+	msm_mpd.iowait_threshold_pct = val;
+	return 0;
+}
+
+#define MPD_ALGO_PARAM(_name, _param) \
+static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
+			struct kobj_attribute *attr, char *buf) \
+{ \
+	return snprintf(buf, PAGE_SIZE, "%d\n", _param); \
+} \
+static ssize_t msm_mpd_attr_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+	int ret = 0; \
+	uint32_t val; \
+	uint32_t old_val; \
+	mutex_lock(&msm_mpd.lock); \
+	ret = kstrtouint(buf, 10, &val); \
+	if (ret) { \
+		pr_err("Invalid input %s for %s %d\n", \
+				buf, __stringify(_name), ret);\
+		return 0; \
+	} \
+	old_val = _param; \
+	_param = val; \
+	ret = msm_mpd_scm_set_algo_params(&msm_mpd.mp_param); \
+	if (ret) { \
+		pr_err("Error %d returned when setting algo param %s to %d\n",\
+				ret, __stringify(_name), val); \
+		_param = old_val; \
+	} \
+	mutex_unlock(&msm_mpd.lock); \
+	return count; \
+}
+
+#define MPD_PARAM(_name, _param) \
+static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
+			struct kobj_attribute *attr, char *buf) \
+{ \
+	return snprintf(buf, PAGE_SIZE, "%d\n", _param); \
+} \
+static ssize_t msm_mpd_attr_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+	int ret = 0; \
+	uint32_t val; \
+	uint32_t old_val; \
+	mutex_lock(&msm_mpd.lock); \
+	ret = kstrtouint(buf, 10, &val); \
+	if (ret) { \
+		pr_err("Invalid input %s for %s %d\n", \
+				buf, __stringify(_name), ret);\
+		return 0; \
+	} \
+	old_val = _param; \
+	ret = msm_mpd_set_##_name(val); \
+	if (ret) { \
+		pr_err("Error %d returned when setting algo param %s to %d\n",\
+				ret, __stringify(_name), val); \
+		_param = old_val; \
+	} \
+	mutex_unlock(&msm_mpd.lock); \
+	return count; \
+}
+
+#define MPD_RW_ATTRIB(i, _name) \
+	msm_mpd.attrib._name.attr.name = __stringify(_name); \
+	msm_mpd.attrib._name.attr.mode = S_IRUGO | S_IWUSR; \
+	msm_mpd.attrib._name.show = msm_mpd_attr_##_name##_show; \
+	msm_mpd.attrib._name.store = msm_mpd_attr_##_name##_store; \
+	msm_mpd.attrib.attrib_group.attrs[i] = &msm_mpd.attrib._name.attr;
+
+MPD_PARAM(enabled, msm_mpd.enabled);
+MPD_PARAM(rq_avg_poll_ms, msm_mpd.rq_avg_poll_ms);
+MPD_PARAM(iowait_threshold_pct, msm_mpd.iowait_threshold_pct);
+MPD_ALGO_PARAM(em_win_size_min_us, msm_mpd.mp_param.em_win_size_min_us);
+MPD_ALGO_PARAM(em_win_size_max_us, msm_mpd.mp_param.em_win_size_max_us);
+MPD_ALGO_PARAM(em_max_util_pct, msm_mpd.mp_param.em_max_util_pct);
+MPD_ALGO_PARAM(mp_em_rounding_point_min,
+				msm_mpd.mp_param.mp_em_rounding_point_min);
+MPD_ALGO_PARAM(mp_em_rounding_point_max,
+				msm_mpd.mp_param.mp_em_rounding_point_max);
+MPD_ALGO_PARAM(online_util_pct_min, msm_mpd.mp_param.online_util_pct_min);
+MPD_ALGO_PARAM(online_util_pct_max, msm_mpd.mp_param.online_util_pct_max);
+MPD_ALGO_PARAM(slack_time_min_us, msm_mpd.mp_param.slack_time_min_us);
+MPD_ALGO_PARAM(slack_time_max_us, msm_mpd.mp_param.slack_time_max_us);
+MPD_ALGO_PARAM(hp_up_max_ms, hp_latencies.hp_up_max_ms);
+MPD_ALGO_PARAM(hp_up_ms, hp_latencies.hp_up_ms);
+MPD_ALGO_PARAM(hp_up_count, hp_latencies.hp_up_count);
+MPD_ALGO_PARAM(hp_dw_max_ms, hp_latencies.hp_dw_max_ms);
+MPD_ALGO_PARAM(hp_dw_ms, hp_latencies.hp_dw_ms);
+MPD_ALGO_PARAM(hp_dw_count, hp_latencies.hp_dw_count);
+
+static int __devinit msm_mpd_probe(struct platform_device *pdev)
+{
+	struct kobject *module_kobj = NULL;
+	int ret = 0;
+	const int attr_count = 19;
+	struct msm_mpd_algo_param *param = NULL;
+
+	param = pdev->dev.platform_data;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("Cannot find kobject for module %s\n", KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto done;
+	}
+
+	msm_mpd.attrib.attrib_group.attrs =
+		kzalloc(attr_count * sizeof(struct attribute *), GFP_KERNEL);
+	if (!msm_mpd.attrib.attrib_group.attrs) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	MPD_RW_ATTRIB(0, enabled);
+	MPD_RW_ATTRIB(1, rq_avg_poll_ms);
+	MPD_RW_ATTRIB(2, iowait_threshold_pct);
+	MPD_RW_ATTRIB(3, em_win_size_min_us);
+	MPD_RW_ATTRIB(4, em_win_size_max_us);
+	MPD_RW_ATTRIB(5, em_max_util_pct);
+	MPD_RW_ATTRIB(6, mp_em_rounding_point_min);
+	MPD_RW_ATTRIB(7, mp_em_rounding_point_max);
+	MPD_RW_ATTRIB(8, online_util_pct_min);
+	MPD_RW_ATTRIB(9, online_util_pct_max);
+	MPD_RW_ATTRIB(10, slack_time_min_us);
+	MPD_RW_ATTRIB(11, slack_time_max_us);
+	MPD_RW_ATTRIB(12, hp_up_max_ms);
+	MPD_RW_ATTRIB(13, hp_up_ms);
+	MPD_RW_ATTRIB(14, hp_up_count);
+	MPD_RW_ATTRIB(15, hp_dw_max_ms);
+	MPD_RW_ATTRIB(16, hp_dw_ms);
+	MPD_RW_ATTRIB(17, hp_dw_count);
+
+	msm_mpd.attrib.attrib_group.attrs[18] = NULL;
+	ret = sysfs_create_group(module_kobj, &msm_mpd.attrib.attrib_group);
+	if (ret)
+		pr_err("Unable to create sysfs objects :%d\n", ret);
+
+	msm_mpd.rq_avg_poll_ms = DEFAULT_RQ_AVG_POLL_MS;
+
+	memcpy(&msm_mpd.mp_param, param, sizeof(struct msm_mpd_algo_param));
+
+	debugfs_base = debugfs_create_dir("msm_mpdecision", NULL);
+	if (!debugfs_base) {
+		pr_err("Cannot create debugfs base msm_mpdecision\n");
+		ret = -ENOENT;
+		goto done;
+	}
+
+done:
+	if (ret && debugfs_base)
+		debugfs_remove(debugfs_base);
+
+	return ret;
+}
+
+static int __devexit msm_mpd_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver msm_mpd_driver = {
+	.probe	= msm_mpd_probe,
+	.remove	= __devexit_p(msm_mpd_remove),
+	.driver	= {
+		.name	= "msm_mpdecision",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init msm_mpdecision_init(void)
+{
+	int cpu;
+	if (!msm_mpd_enabled) {
+		pr_info("Not enabled\n");
+		return 0;
+	}
+
+	num_present_hundreds = 100 * num_present_cpus();
+
+	hrtimer_init(&msm_mpd.slack_timer, CLOCK_MONOTONIC,
+			HRTIMER_MODE_REL_PINNED);
+	msm_mpd.slack_timer.function = msm_mpd_slack_timer;
+
+	for_each_possible_cpu(cpu) {
+		hrtimer_init(&per_cpu(rq_avg_poll_timer, cpu),
+			     CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
+		per_cpu(rq_avg_poll_timer, cpu).function
+				= msm_mpd_rq_avg_poll_timer;
+	}
+	mutex_init(&msm_mpd.lock);
+	init_waitqueue_head(&msm_mpd.wait_q);
+	init_waitqueue_head(&msm_mpd.wait_hpq);
+	return platform_driver_register(&msm_mpd_driver);
+}
+late_initcall(msm_mpdecision_init);
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 2d61504..404b350 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -236,7 +236,7 @@
 	int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
 			       cpu_is_msm8930() || cpu_is_msm8930aa() ||
 			       cpu_is_msm9615() || cpu_is_msm8627() ||
-			       cpu_is_msm8960ab();
+			       cpu_is_msm8960ab() || cpu_is_apq8064ab();
 
 	if (xo_voter->mode == mode)
 		return 0;
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index e3b250b..405b73f 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -55,7 +55,15 @@
 
 struct pil_device;
 
+#ifdef CONFIG_MSM_PIL
 extern struct pil_device *msm_pil_register(struct pil_desc *desc);
 extern void msm_pil_unregister(struct pil_device *pil);
+#else
+static inline struct pil_device *msm_pil_register(struct pil_desc *desc)
+{
+	return NULL;
+}
+static inline void msm_pil_unregister(struct pil_device *pil) { }
+#endif
 
 #endif
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 73248db..bccbce2 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -21,15 +21,22 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/smp.h>
+#include <linux/miscdevice.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
 
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
 #include <mach/socinfo.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.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
@@ -63,6 +70,14 @@
 	unsigned long start_addr;
 	struct clk *xo;
 	struct pil_device *pil;
+	struct miscdevice misc_dev;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	int crash_shutdown;
+	int irq;
+	void *pil_handle;
+	struct ramdump_device *ramdump_dev;
+	struct ramdump_device *smem_ramdump_dev;
 };
 
 static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -308,11 +323,160 @@
 	.proxy_unvote = remove_gss_proxy_votes,
 };
 
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_gss_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("GSS subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void restart_gss(struct gss_data *drv)
+{
+	log_gss_sfr();
+	subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	struct gss_data *drv = data;
+
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (drv->crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+			"Probable err_fatal on the GSS. "
+			"Calling subsystem restart...\n");
+		restart_gss(drv);
+	}
+}
+
+static int gss_shutdown(const struct subsys_desc *desc)
+{
+	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+	pil_force_shutdown("gss");
+	disable_irq_nosync(drv->irq);
+
+	return 0;
+}
+
+static int gss_powerup(const struct subsys_desc *desc)
+{
+	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+	pil_force_boot("gss");
+	enable_irq(drv->irq);
+	return 0;
+}
+
+void gss_crash_shutdown(const struct subsys_desc *desc)
+{
+	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+	drv->crash_shutdown = 1;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment gss_segments[] = {
+	{0x89000000, 0x00D00000}
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x80000000, 0x00200000},
+};
+
+static int gss_ramdump(int enable, const struct subsys_desc *desc)
+{
+	int ret;
+	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+	if (enable) {
+		ret = do_ramdump(drv->ramdump_dev, gss_segments,
+				ARRAY_SIZE(gss_segments));
+		if (ret < 0) {
+			pr_err("Unable to dump gss memory\n");
+			return ret;
+		}
+
+		ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+			ARRAY_SIZE(smem_segments));
+		if (ret < 0) {
+			pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
+{
+	struct gss_data *drv = dev_id;
+
+	pr_err("Watchdog bite received from GSS!\n");
+	restart_gss(drv);
+
+	return IRQ_HANDLED;
+}
+
+static int gss_open(struct inode *inode, struct file *filp)
+{
+	void *ret;
+	struct miscdevice *c = filp->private_data;
+	struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
+
+	drv->pil_handle = ret = pil_get("gss");
+	if (!ret)
+		pr_debug("%s - pil_get returned NULL\n", __func__);
+
+	return 0;
+}
+
+static int gss_release(struct inode *inode, struct file *filp)
+{
+	struct miscdevice *c = filp->private_data;
+	struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
+
+	pil_put(drv->pil_handle);
+	pr_debug("%s pil_put called on GSS\n", __func__);
+
+	return 0;
+}
+
+const struct file_operations gss_file_ops = {
+	.open = gss_open,
+	.release = gss_release,
+	.owner = THIS_MODULE,
+};
+
 static int __devinit pil_gss_probe(struct platform_device *pdev)
 {
 	struct gss_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -344,6 +508,10 @@
 	if (IS_ERR(drv->xo))
 		return PTR_ERR(drv->xo);
 
+	drv->irq = platform_get_irq(pdev, 0);
+	if (drv->irq < 0)
+		return drv->irq;
+
 	desc->name = "gss";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
@@ -363,13 +531,71 @@
 	if (IS_ERR(drv->pil)) {
 		return PTR_ERR(drv->pil);
 	}
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+			smsm_state_cb, drv);
+	if (ret < 0)
+		dev_warn(&pdev->dev, "Unable to register SMSM callback\n");
+
+	drv->subsys_desc.name = "gss";
+	drv->subsys_desc.shutdown = gss_shutdown;
+	drv->subsys_desc.powerup = gss_powerup;
+	drv->subsys_desc.ramdump = gss_ramdump;
+	drv->subsys_desc.crash_shutdown = gss_crash_shutdown;
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
+	}
+
+	drv->misc_dev.minor = MISC_DYNAMIC_MINOR;
+	drv->misc_dev.name = "gss";
+	drv->misc_dev.fops = &gss_file_ops;
+	ret = misc_register(&drv->misc_dev);
+	if (ret)
+		goto err_misc;
+
+	drv->ramdump_dev = create_ramdump_device("gss");
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump;
+	}
+
+	drv->smem_ramdump_dev = create_ramdump_device("smem-gss");
+	if (!drv->smem_ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_smem;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drv->irq, gss_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "gss_a5_wdog", drv);
+	if (ret < 0)
+		goto err;
 	return 0;
+err:
+	destroy_ramdump_device(drv->smem_ramdump_dev);
+err_smem:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	misc_deregister(&drv->misc_dev);
+err_misc:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	msm_pil_unregister(drv->pil);
+	return ret;
 }
 
 static int __devexit pil_gss_remove(struct platform_device *pdev)
 {
 	struct gss_data *drv = platform_get_drvdata(pdev);
+
+	destroy_ramdump_device(drv->smem_ramdump_dev);
+	destroy_ramdump_device(drv->ramdump_dev);
+	misc_deregister(&drv->misc_dev);
+	subsys_unregister(drv->subsys);
 	msm_pil_unregister(drv->pil);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 5e67d4f..0207f0b 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -172,7 +172,7 @@
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
 	if (!res)
 		return -EINVAL;
 	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
@@ -180,7 +180,8 @@
 	if (!drv->reg_base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					    "metadata_base");
 	if (res) {
 		drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
 						  resource_size(res));
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 8344496..ecb3800 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -19,11 +19,19 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
 
+#include "modem_notifier.h"
 #include "peripheral-loader.h"
 #include "scm-pas.h"
+#include "ramdump.h"
 
 #define MARM_BOOT_CONTROL		0x0010
 #define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
@@ -46,12 +54,22 @@
 #define PLL_ENA_MARM			(MSM_CLK_CTL_BASE + 0x3500)
 #define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
 #define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
+#define MSS_MODEM_RESET			(MSM_CLK_CTL_BASE + 0x2C48)
 
 struct modem_data {
 	void __iomem *base;
+	void __iomem *wdog;
 	unsigned long start_addr;
 	struct pil_device *pil;
 	struct clk *xo;
+	struct notifier_block notifier;
+	int ignore_smsm_ack;
+	int irq;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	struct delayed_work unlock_work;
+	struct work_struct fatal_work;
+	struct ramdump_device *ramdump_dev;
 };
 
 static int make_modem_proxy_votes(struct pil_desc *pil)
@@ -161,7 +179,7 @@
 	return 0;
 }
 
-static int modem_shutdown(struct pil_desc *pil)
+static int modem_pil_shutdown(struct pil_desc *pil)
 {
 	u32 reg;
 
@@ -203,7 +221,7 @@
 static struct pil_reset_ops pil_modem_ops = {
 	.init_image = modem_init_image,
 	.auth_and_reset = modem_reset,
-	.shutdown = modem_shutdown,
+	.shutdown = modem_pil_shutdown,
 	.proxy_vote = make_modem_proxy_votes,
 	.proxy_unvote = remove_modem_proxy_votes,
 };
@@ -232,11 +250,166 @@
 	.proxy_unvote = remove_modem_proxy_votes,
 };
 
+static void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+
+	/* If modem hasn't already crashed, send SMSM_RESET. */
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+		modem_unregister_notifier(&drv->notifier);
+		smsm_reset_modem(SMSM_RESET);
+	}
+
+	/* Wait to allow the modem to clean up caches etc. */
+	mdelay(5);
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	struct modem_data *drv = dev_id;
+
+	schedule_work(&drv->fatal_work);
+	disable_irq_nosync(drv->irq);
+
+	return IRQ_HANDLED;
+}
+
+static void modem_unlock_timeout(struct work_struct *work)
+{
+	struct modem_data *drv;
+	struct delayed_work *dwork = to_delayed_work(work);
+
+	pr_crit("Timeout waiting for modem to unlock.\n");
+
+	drv = container_of(dwork, struct modem_data, unlock_work);
+	/* The unlock didn't work, clear the reset */
+	writel_relaxed(0x0, MSS_MODEM_RESET);
+	mb();
+
+	subsystem_restart_dev(drv->subsys);
+	enable_irq(drv->irq);
+}
+
+static void modem_fatal_fn(struct work_struct *work)
+{
+	u32 modem_state;
+	u32 panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	u32 reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR;
+	struct modem_data *drv;
+
+	drv = container_of(work, struct modem_data, fatal_work);
+
+	pr_err("Watchdog bite received from modem!\n");
+
+	modem_state = smsm_get_state(SMSM_MODEM_STATE);
+	pr_err("Modem SMSM state = 0x%x!\n", modem_state);
+
+	if (modem_state == 0 || modem_state & panic_smsm_states) {
+		subsystem_restart_dev(drv->subsys);
+		enable_irq(drv->irq);
+	} else if (modem_state & reset_smsm_states) {
+		pr_err("User-invoked system reset/powerdown.");
+		kernel_restart(NULL);
+	} else {
+		unsigned long timeout = msecs_to_jiffies(6000);
+
+		pr_err("Modem AHB locked up. Trying to free up modem!\n");
+
+		writel_relaxed(0x3, MSS_MODEM_RESET);
+		/*
+		 * If we are still alive (allowing for the 5 second
+		 * delayed-panic-reboot), the modem is either still wedged or
+		 * SMSM didn't come through. Force panic in that case.
+		 */
+		schedule_delayed_work(&drv->unlock_work, timeout);
+	}
+}
+
+static int modem_notif_handler(struct notifier_block *nb, unsigned long code,
+				void *p)
+{
+	struct modem_data *drv = container_of(nb, struct modem_data, notifier);
+
+	if (code == MODEM_NOTIFIER_START_RESET) {
+		if (drv->ignore_smsm_ack) {
+			drv->ignore_smsm_ack = 0;
+		} else {
+			pr_err("Modem error fatal'ed.");
+			subsystem_restart_dev(drv->subsys);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	/*
+	 * If the modem didn't already crash, setting SMSM_RESET here will help
+	 * flush caches etc. The ignore_smsm_ack flag is set to ignore the
+	 * SMSM_RESET notification that is generated due to the modem settings
+	 * its own SMSM_RESET bit in response to the apps setting the apps
+	 * SMSM_RESET bit.
+	 */
+	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+		drv->ignore_smsm_ack = 1;
+		smsm_reset_modem(SMSM_RESET);
+	}
+
+	/* Disable the modem watchdog to allow clean modem bootup */
+	writel_relaxed(0x0, drv->wdog + 0x8);
+	/*
+	 * The write above needs to go through before the modem is powered up
+	 * again.
+	 */
+	mb();
+	/* Wait here to allow the modem to clean up caches, etc. */
+	msleep(20);
+
+	pil_force_shutdown("modem");
+	disable_irq_nosync(drv->irq);
+
+	return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+	int ret;
+
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	ret = pil_force_boot("modem");
+	enable_irq(drv->irq);
+
+	return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment modem_segments[] = {
+	{ 0x42F00000, 0x46000000 - 0x42F00000 },
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct modem_data *drv;
+
+	drv = container_of(subsys, struct modem_data, subsys_desc);
+	if (enable)
+		return do_ramdump(drv->ramdump_dev, modem_segments,
+				ARRAY_SIZE(modem_segments));
+	else
+		return 0;
+}
+
 static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
 {
 	struct modem_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -247,6 +420,10 @@
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
+	drv->irq = platform_get_irq(pdev, 0);
+	if (drv->irq < 0)
+		return drv->irq;
+
 	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 	if (!drv->base)
 		return -ENOMEM;
@@ -259,6 +436,14 @@
 	if (!desc)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->wdog = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->wdog)
+		return -ENOMEM;
+
 	desc->name = "modem";
 	desc->depends_on = "q6";
 	desc->dev = &pdev->dev;
@@ -273,16 +458,61 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil)) {
+	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
+
+	drv->notifier.notifier_call = modem_notif_handler,
+	ret = modem_register_notifier(&drv->notifier);
+	if (ret)
+		goto err_notify;
+
+	drv->subsys_desc.name = "modem";
+	drv->subsys_desc.shutdown = modem_shutdown;
+	drv->subsys_desc.powerup = modem_powerup;
+	drv->subsys_desc.ramdump = modem_ramdump;
+	drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+
+	INIT_WORK(&drv->fatal_work, modem_fatal_fn);
+	INIT_DELAYED_WORK(&drv->unlock_work, modem_unlock_timeout);
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
 	}
+
+	drv->ramdump_dev = create_ramdump_device("modem");
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drv->irq, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_watchdog", drv);
+	if (ret)
+		goto err_irq;
 	return 0;
+
+err_irq:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	modem_unregister_notifier(&drv->notifier);
+err_notify:
+	msm_pil_unregister(drv->pil);
+	return ret;
 }
 
 static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
 {
 	struct modem_data *drv = platform_get_drvdata(pdev);
+
+	destroy_ramdump_device(drv->ramdump_dev);
+	subsys_unregister(drv->subsys);
+	modem_unregister_notifier(&drv->notifier);
 	msm_pil_unregister(drv->pil);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 01cdb0b..1e39043 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -233,7 +233,7 @@
 	int ret;
 	uint32_t regval;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
 	if (!res)
 		return -EINVAL;
 
@@ -246,14 +246,14 @@
 	if (!drv->base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
 	if (!res)
 		return -EINVAL;
 
 	drv->reset_base = devm_ioremap(&pdev->dev, res->start,
 					resource_size(res));
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
 	if (!res)
 		return -EINVAL;
 
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 28b9dee..1a226de 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -19,9 +19,15 @@
 #include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
 
+#include "ramdump.h"
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
@@ -60,11 +66,34 @@
 #define Q6_STRAP_TCM_BASE	(0x28C << 15)
 #define Q6_STRAP_TCM_CONFIG	0x28B
 
+#define SCM_Q6_NMI_CMD		0x1
+
+/**
+ * struct q6v3_data - LPASS driver data
+ * @base: register base
+ * @wk_base: wakeup register base
+ * @wd_base: watchdog register base
+ * @start_addr: address that processor starts running at
+ * @irq: watchdog irq
+ * @pil: peripheral handle
+ * @subsys: subsystem restart handle
+ * @subsys_desc: subsystem restart descriptor
+ * @fatal_wrk: fatal error workqueue
+ * @pll: pll clock handle
+ * @ramdump_dev: ramdump device
+ */
 struct q6v3_data {
 	void __iomem *base;
+	void __iomem *wk_base;
+	void __iomem *wd_base;
 	unsigned long start_addr;
+	int irq;
 	struct pil_device *pil;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	struct work_struct fatal_wrk;
 	struct clk *pll;
+	struct ramdump_device *ramdump_dev;
 };
 
 static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -198,11 +227,96 @@
 	.proxy_unvote = pil_q6v3_remove_proxy_votes,
 };
 
+static void q6_fatal_fn(struct work_struct *work)
+{
+	struct q6v3_data *drv = container_of(work, struct q6v3_data, fatal_wrk);
+
+	pr_err("Watchdog bite received from Q6!\n");
+	subsystem_restart_dev(drv->subsys);
+	enable_irq(drv->irq);
+}
+
+static void send_q6_nmi(struct q6v3_data *drv)
+{
+	/* Send NMI to QDSP6 via an SCM call. */
+	scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+
+	/* Wakeup the Q6 */
+	writel_relaxed(0x2000, drv->wk_base + 0x1c);
+	/* Q6 requires atleast 100ms to dump caches etc.*/
+	mdelay(100);
+	pr_info("Q6 NMI was sent.\n");
+}
+
+static int lpass_q6_shutdown(const struct subsys_desc *subsys)
+{
+	struct q6v3_data *drv;
+
+	drv = container_of(subsys, struct q6v3_data, subsys_desc);
+	send_q6_nmi(drv);
+	writel_relaxed(0x0, drv->wd_base + 0x24);
+	mb();
+
+	pil_force_shutdown("q6");
+	disable_irq_nosync(drv->irq);
+
+	return 0;
+}
+
+static int lpass_q6_powerup(const struct subsys_desc *subsys)
+{
+	struct q6v3_data *drv;
+	int ret;
+
+	drv = container_of(subsys, struct q6v3_data, subsys_desc);
+	ret = pil_force_boot("q6");
+	enable_irq(drv->irq);
+	return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment q6_segments[] = {
+	{ 0x46700000, 0x47f00000 - 0x46700000 },
+	{ 0x28400000, 0x12800 }
+};
+
+static int lpass_q6_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct q6v3_data *drv;
+
+	drv = container_of(subsys, struct q6v3_data, subsys_desc);
+	if (enable)
+		return do_ramdump(drv->ramdump_dev, q6_segments,
+				ARRAY_SIZE(q6_segments));
+	else
+		return 0;
+}
+
+static void lpass_q6_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct q6v3_data *drv;
+
+	drv = container_of(subsys, struct q6v3_data, subsys_desc);
+	send_q6_nmi(drv);
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+	int ret;
+	struct q6v3_data *drv = dev_id;
+
+	ret = schedule_work(&drv->fatal_wrk);
+	disable_irq_nosync(drv->irq);
+
+	return IRQ_HANDLED;
+}
+
 static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
 {
 	struct q6v3_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -217,14 +331,34 @@
 	if (!drv->base)
 		return -ENOMEM;
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!drv)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->wk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->wk_base)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res)
+		return -EINVAL;
+
+	drv->wd_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->wd_base)
+		return -ENOMEM;
+
+	drv->irq = platform_get_irq(pdev, 0);
+	if (drv->irq < 0)
+		return drv->irq;
+
 	drv->pll = devm_clk_get(&pdev->dev, "pll4");
 	if (IS_ERR(drv->pll))
 		return PTR_ERR(drv->pll);
 
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
 	desc->name = "q6";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
@@ -239,15 +373,51 @@
 	}
 
 	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil)) {
+	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
+
+	drv->subsys_desc.name = "lpass";
+	drv->subsys_desc.shutdown = lpass_q6_shutdown;
+	drv->subsys_desc.powerup = lpass_q6_powerup;
+	drv->subsys_desc.ramdump = lpass_q6_ramdump;
+	drv->subsys_desc.crash_shutdown = lpass_q6_crash_shutdown;
+
+	INIT_WORK(&drv->fatal_wrk, q6_fatal_fn);
+
+	drv->ramdump_dev = create_ramdump_device("lpass");
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump;
 	}
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drv->irq, lpass_wdog_bite_irq,
+			       IRQF_TRIGGER_RISING, "lpass_wdog", drv);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to request wdog irq.\n");
+		goto err_irq;
+	}
+
 	return 0;
+err_irq:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	msm_pil_unregister(drv->pil);
+	return ret;
 }
 
 static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
 {
 	struct q6v3_data *drv = platform_get_drvdata(pdev);
+	subsys_unregister(drv->subsys);
+	destroy_ramdump_device(drv->ramdump_dev);
 	msm_pil_unregister(drv->pil);
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 1fdd342..7b45a0e 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -266,20 +266,21 @@
 	of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
 			     &drv->self_auth);
 	if (drv->self_auth) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						    "rmb_base");
 		drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
 					     resource_size(res));
 		if (!drv->rmb_base)
 			return -ENOMEM;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
 	drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
 					resource_size(res));
 	if (!drv->restart_reg)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clamp_reg");
 	drv->io_clamp_reg = devm_ioremap(&pdev->dev, res->start,
 					resource_size(res));
 	if (!drv->io_clamp_reg)
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 772031b..f4e8844 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -205,14 +205,14 @@
 		return ERR_PTR(-ENOMEM);
 	platform_set_drvdata(pdev, drv);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
 	if (!res)
 		return ERR_PTR(-EINVAL);
 	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
 				     resource_size(res));
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
 	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
 	if (!drv->axi_halt_base)
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 3040a31..dbb4408 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -20,11 +20,17 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/wcnss_wlan.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
+#include "ramdump.h"
+#include "smd_private.h"
 
 #define RIVA_PMU_A2XB_CFG		0xB8
 #define RIVA_PMU_A2XB_CFG_EN		BIT(0)
@@ -82,6 +88,13 @@
 	struct clk *xo;
 	struct regulator *pll_supply;
 	struct pil_device *pil;
+	int irq;
+	int crash;
+	int rst_in_progress;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	struct delayed_work cancel_work;
+	struct ramdump_device *ramdump_dev;
 };
 
 static bool cxo_is_needed(struct riva_data *drv)
@@ -272,6 +285,160 @@
 	.proxy_unvote = pil_riva_remove_proxy_vote,
 };
 
+static int enable_riva_ssr;
+
+static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		return ret;
+
+	if (enable_riva_ssr)
+		pr_info("Subsystem restart activated for riva.\n");
+
+	return 0;
+}
+module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
+		 &enable_riva_ssr, S_IRUGO | S_IWUSR);
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+			       uint32_t new_state)
+{
+	struct riva_data *drv = data;
+	char *smem_reset_reason;
+	char buffer[81];
+	unsigned smem_reset_size;
+	unsigned size;
+
+	drv->crash = true;
+	if (!(new_state & SMSM_RESET))
+		return;
+
+	if (drv->rst_in_progress) {
+		pr_err("riva: Ignoring smsm reset req, restart in progress\n");
+		return;
+	}
+
+	pr_err("riva: smsm state changed to smsm reset\n");
+
+	smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+		&smem_reset_size);
+
+	if (!smem_reset_reason || !smem_reset_size) {
+		pr_err("wcnss subsystem failure reason:\n"
+		       "(unknown, smem_get_entry failed)");
+	} else if (!smem_reset_reason[0]) {
+		pr_err("wcnss subsystem failure reason:\n"
+		       "(unknown, init string found)");
+	} else {
+		size = smem_reset_size < sizeof(buffer) ? smem_reset_size :
+				(sizeof(buffer) - 1);
+		memcpy(buffer, smem_reset_reason, size);
+		buffer[size] = '\0';
+		pr_err("wcnss subsystem failure reason: %s\n", buffer);
+		memset(smem_reset_reason, 0, smem_reset_size);
+		wmb();
+	}
+
+	drv->rst_in_progress = 1;
+	subsystem_restart_dev(drv->subsys);
+}
+
+static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+	struct riva_data *drv = dev_id;
+
+	drv->crash = true;
+	if (drv->rst_in_progress) {
+		pr_err("Ignoring riva bite irq, restart in progress\n");
+		return IRQ_HANDLED;
+	}
+	if (!enable_riva_ssr)
+		panic("Watchdog bite received from Riva");
+
+	drv->rst_in_progress = 1;
+	subsystem_restart_dev(drv->subsys);
+
+	return IRQ_HANDLED;
+}
+
+static void riva_post_bootup(struct work_struct *work)
+{
+	struct platform_device *pdev = wcnss_get_platform_device();
+	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+
+	wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
+}
+
+static int riva_shutdown(const struct subsys_desc *desc)
+{
+	struct riva_data *drv;
+
+	drv = container_of(desc, struct riva_data, subsys_desc);
+	pil_force_shutdown("wcnss");
+	flush_delayed_work(&drv->cancel_work);
+	wcnss_flush_delayed_boot_votes();
+	disable_irq_nosync(drv->irq);
+
+	return 0;
+}
+
+static int riva_powerup(const struct subsys_desc *desc)
+{
+	struct riva_data *drv;
+	struct platform_device *pdev = wcnss_get_platform_device();
+	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+	int ret = 0;
+
+	drv = container_of(desc, struct riva_data, subsys_desc);
+	if (pdev && pwlanconfig) {
+		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
+					WCNSS_WLAN_SWITCH_ON);
+		if (!ret)
+			pil_force_boot("wcnss");
+	}
+	drv->rst_in_progress = 0;
+	enable_irq(drv->irq);
+	schedule_delayed_work(&drv->cancel_work, msecs_to_jiffies(5000));
+
+	return ret;
+}
+
+/*
+ * 7MB RAM segments for Riva SS;
+ * Riva 1.1 0x8f000000 - 0x8f700000
+ * Riva 1.0 0x8f200000 - 0x8f700000
+ */
+static struct ramdump_segment riva_segments[] = {
+	{0x8f000000, 0x8f700000 - 0x8f000000}
+};
+
+static int riva_ramdump(int enable, const struct subsys_desc *desc)
+{
+	struct riva_data *drv;
+
+	drv = container_of(desc, struct riva_data, subsys_desc);
+
+	if (enable)
+		return do_ramdump(drv->ramdump_dev, riva_segments,
+				ARRAY_SIZE(riva_segments));
+	else
+		return 0;
+}
+
+/* Riva crash handler */
+static void riva_crash_shutdown(const struct subsys_desc *desc)
+{
+	struct riva_data *drv;
+
+	drv = container_of(desc, struct riva_data, subsys_desc);
+	pr_err("riva crash shutdown %d\n", drv->crash);
+	if (drv->crash != true)
+		smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
 static int __devinit pil_riva_probe(struct platform_device *pdev)
 {
 	struct riva_data *drv;
@@ -317,6 +484,10 @@
 		}
 	}
 
+	drv->irq = platform_get_irq(pdev, 0);
+	if (drv->irq < 0)
+		return drv->irq;
+
 	desc->name = "wcnss";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
@@ -337,13 +508,60 @@
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
+
+	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
+					smsm_state_cb_hdlr, drv);
+	if (ret < 0)
+		goto err_smsm;
+
+	drv->subsys_desc.name = "wcnss";
+	drv->subsys_desc.shutdown = riva_shutdown;
+	drv->subsys_desc.powerup = riva_powerup;
+	drv->subsys_desc.ramdump = riva_ramdump;
+	drv->subsys_desc.crash_shutdown = riva_crash_shutdown;
+
+	INIT_DELAYED_WORK(&drv->cancel_work, riva_post_bootup);
+
+	drv->ramdump_dev = create_ramdump_device("riva");
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump;
+	}
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
+			IRQF_TRIGGER_HIGH, "riva_wdog", drv);
+	if (ret < 0)
+		goto err;
+
 	return 0;
+err:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+					smsm_state_cb_hdlr, drv);
+err_smsm:
+	msm_pil_unregister(drv->pil);
+	return ret;
 }
 
 static int __devexit pil_riva_remove(struct platform_device *pdev)
 {
 	struct riva_data *drv = platform_get_drvdata(pdev);
+
+	subsys_unregister(drv->subsys);
+	destroy_ramdump_device(drv->ramdump_dev);
+	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+					smsm_state_cb_hdlr, drv);
 	msm_pil_unregister(drv->pil);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 1ccde72..e331296 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -388,7 +388,8 @@
 	struct pil_desc *desc;
 	int rc;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					    "wrapper_base");
 	if (!res)
 		return -EINVAL;
 
@@ -402,7 +403,7 @@
 	if (!drv->venus_wrapper_base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_base");
 	if (!res)
 		return -EINVAL;
 
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 700f966..3b31b9f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -28,19 +28,28 @@
 #include <mach/msm_iomap.h>
 #include "pm.h"
 
-#define MSM_CORE1_RESET		0xA8600590
-#define MSM_CORE1_STATUS_MSK	0x02800000
+#define CORE_RESET_BASE		0xA8600590
+#define MSM_CORE_STATUS_MSK	0x02800000
 
 /*
  * control for which core is the next to come out of the secondary
  * boot "holding pen"
  */
-int pen_release = -1;
+volatile int pen_release = -1;
 
-static bool cold_boot_done;
+static DEFINE_PER_CPU(bool, cold_boot_done);
+
+struct per_cpu_data {
+	unsigned int reset_off;
+	unsigned int offset;
+	unsigned int ipc_irq;
+	void __iomem *reset_core_base;
+};
 
 static uint32_t *msm8625_boot_vector;
-static void __iomem *reset_core1_base;
+
+
+static struct per_cpu_data cpu_data[CONFIG_NR_CPUS];
 
 /*
  * Write pen_release in a way that is guaranteed to be visible to all
@@ -65,7 +74,8 @@
 /*
  * MP_CORE_IPC will be used to generate interrupt and can be used by either
  * of core.
- * To bring core1 out of GDFS we need to raise the SPI using the MP_CORE_IPC.
+ * To bring secondary cores out of GDFS we need to raise the SPI using the
+ * MP_CORE_IPC.
  */
 static void raise_clear_spi(unsigned int cpu, bool set)
 {
@@ -110,10 +120,10 @@
 	 */
 	write_pen_release(-1);
 
-	/* clear the IPC1(SPI-8) pending SPI */
+	/* clear the IPC pending SPI */
 	if (power_collapsed) {
-		raise_clear_spi(1, false);
-		clear_pending_spi(MSM8625_INT_ACSR_MP_CORE_IPC1);
+		raise_clear_spi(cpu, false);
+		clear_pending_spi(cpu_data[cpu].ipc_irq);
 		power_collapsed = 0;
 	}
 
@@ -124,7 +134,7 @@
 	spin_unlock(&boot_lock);
 }
 
-static int  __cpuinit msm8625_release_secondary(void)
+static int  __cpuinit msm8625_release_secondary(unsigned int cpu)
 {
 	void __iomem *base_ptr;
 	int value = 0;
@@ -137,33 +147,35 @@
 	 */
 	timeout = jiffies + usecs_to_jiffies(20);
 	while (time_before(jiffies, timeout)) {
-		value = __raw_readl(MSM_CFG_CTL_BASE + 0x3c);
-		if ((value & MSM_CORE1_STATUS_MSK) ==
-				MSM_CORE1_STATUS_MSK)
+		value = __raw_readl(MSM_CFG_CTL_BASE + cpu_data[cpu].offset);
+		if ((value & MSM_CORE_STATUS_MSK) ==
+				MSM_CORE_STATUS_MSK)
 			break;
 			udelay(1);
 	}
 
 	if (!value) {
-		pr_err("Core 1 cannot be brought out of Reset!!!\n");
+		pr_err("Core %u cannot be brought out of Reset!!!\n", cpu);
 		return -ENODEV;
 	}
 
-	base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+	base_ptr = ioremap_nocache(CORE_RESET_BASE +
+			cpu_data[cpu].reset_off, SZ_4);
 	if (!base_ptr)
 		return -ENODEV;
-	/* Reset core 1 out of reset */
+
+	/* Reset core out of reset */
 	__raw_writel(0x0, base_ptr);
 	mb();
 
-	reset_core1_base = base_ptr;
+	cpu_data[cpu].reset_core_base = base_ptr;
 
 	return 0;
 }
 
-void __iomem *core1_reset_base(void)
+void __iomem *core_reset_base(unsigned int cpu)
 {
-	return reset_core1_base;
+	return cpu_data[cpu].reset_core_base;
 }
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -172,12 +184,12 @@
 
 	preset_lpj = loops_per_jiffy;
 
-	if (cold_boot_done == false) {
-		if (msm8625_release_secondary()) {
-			pr_err("Failed to release secondary core\n");
+	if (per_cpu(cold_boot_done, cpu) == false) {
+		if (msm8625_release_secondary(cpu)) {
+			pr_err("Failed to release core %u\n", cpu);
 			return -ENODEV;
 		}
-		cold_boot_done = true;
+		per_cpu(cold_boot_done, cpu) = true;
 	}
 
 	/*
@@ -200,13 +212,13 @@
 	 * and branch to the address found there.
 	 *
 	 * power_collapsed is the flag which will be updated for Powercollapse.
-	 * Once we are out of PC, as Core1 will be in the state of GDFS which
-	 * needs to be brought out by raising an SPI.
+	 * Once we are out of PC, as secondary cores will be in the state of
+	 * GDFS which needs to be brought out by raising an SPI.
 	 */
 
 	if (power_collapsed) {
-		core1_gic_configure_and_raise();
-		raise_clear_spi(1, true);
+		gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu);
+		raise_clear_spi(cpu, true);
 	} else {
 		gic_raise_softirq(cpumask_of(cpu), 1);
 	}
@@ -247,6 +259,34 @@
 	set_smp_cross_call(gic_raise_softirq);
 }
 
+static void per_cpu_data(unsigned int cpu, unsigned int off,
+	unsigned int off1, unsigned int irq)
+{
+	cpu_data[cpu].reset_off = off;
+	cpu_data[cpu].offset    = off1;
+	cpu_data[cpu].ipc_irq   = irq;
+}
+
+static void enable_boot_remapper(unsigned long bit, unsigned int off)
+{
+	int value;
+
+	/* Enable boot remapper address */
+	value = __raw_readl(MSM_CFG_CTL_BASE + off);
+	__raw_writel(value | bit, MSM_CFG_CTL_BASE + off) ;
+	mb();
+}
+
+static void remapper_address(unsigned long phys, unsigned int off)
+{
+	/*
+	 * Write the address of secondary startup into the
+	 * boot remapper register. The secondary CPU branches to this address.
+	 */
+	__raw_writel(phys, (MSM_CFG_CTL_BASE + off));
+	mb();
+}
+
 static void __init msm8625_boot_vector_init(uint32_t *boot_vector,
 		unsigned long entry)
 {
@@ -260,8 +300,8 @@
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-	int i, value;
-	void __iomem *second_ptr;
+	int i, cpu, value;
+	void __iomem *cpu_ptr;
 
 	/*
 	 * Initialise the present map, which describes the set of CPUs
@@ -272,25 +312,41 @@
 
 	scu_enable(scu_base_addr());
 
-	/*
-	 * Write the address of secondary startup into the
-	 * boot remapper register. The secondary CPU branches to this address.
-	 */
-	__raw_writel(MSM8625_SECONDARY_PHYS, (MSM_CFG_CTL_BASE + 0x34));
-	mb();
-
-	second_ptr = ioremap_nocache(MSM8625_SECONDARY_PHYS, SZ_8);
-	if (!second_ptr) {
-		pr_err("failed to ioremap for secondary core\n");
+	cpu_ptr = ioremap_nocache(MSM8625_CPU_PHYS, SZ_8);
+	if (!cpu_ptr) {
+		pr_err("failed to ioremap for secondary cores\n");
 		return;
 	}
 
-	msm8625_boot_vector_init(second_ptr,
+	msm8625_boot_vector_init(cpu_ptr,
 			virt_to_phys(msm_secondary_startup));
-	iounmap(second_ptr);
 
-	/* Enable boot remapper address: bit 26 for core1 */
-	value = __raw_readl(MSM_CFG_CTL_BASE + 0x30);
-	__raw_writel(value | (0x4 << 24), MSM_CFG_CTL_BASE + 0x30) ;
-	mb();
+	iounmap(cpu_ptr);
+
+	for_each_possible_cpu(cpu) {
+		switch (cpu) {
+		case 0:
+			break;
+		case 1:
+			remapper_address(MSM8625_CPU_PHYS, 0x34);
+			per_cpu_data(cpu, 0x0, 0x3c,
+					MSM8625_INT_ACSR_MP_CORE_IPC1);
+			enable_boot_remapper(BIT(26), 0x30);
+			break;
+		case 2:
+			remapper_address((MSM8625_CPU_PHYS >> 16), 0x4C);
+			per_cpu_data(cpu, 0x8, 0x50,
+					MSM8625_INT_ACSR_MP_CORE_IPC2);
+			enable_boot_remapper(BIT(25), 0x48);
+			break;
+		case 3:
+			value = __raw_readl(MSM_CFG_CTL_BASE + 0x4C);
+			remapper_address(value | MSM8625_CPU_PHYS, 0x4C);
+			per_cpu_data(cpu, 0xC, 0x50,
+					MSM8625_INT_ACSR_MP_CORE_IPC3);
+			enable_boot_remapper(BIT(26), 0x48);
+			break;
+		}
+
+	}
 }
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index f6ed1ea..89003cf 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -42,6 +42,19 @@
  */
 volatile int pen_release = -1;
 
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
 static DEFINE_SPINLOCK(boot_lock);
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -56,6 +69,12 @@
 	gic_secondary_init(0);
 
 	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
 	 * Synchronise with the boot thread.
 	 */
 	spin_lock(&boot_lock);
@@ -165,7 +184,8 @@
 		return krait_release_secondary_sim(0xf9088000, cpu);
 
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab())
+	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab() ||
+						cpu_is_apq8064ab())
 		return krait_release_secondary(0x02088000, cpu);
 
 	if (cpu_is_msm8974())
@@ -176,17 +196,9 @@
 }
 
 DEFINE_PER_CPU(int, cold_boot_done);
-static int cold_boot_flags[] = {
-	0,
-	SCM_FLAG_COLDBOOT_CPU1,
-	SCM_FLAG_COLDBOOT_CPU2,
-	SCM_FLAG_COLDBOOT_CPU3,
-};
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-	int ret;
-	unsigned int flag = 0;
 	unsigned long timeout;
 
 	pr_debug("Starting secondary CPU %d\n", cpu);
@@ -194,19 +206,8 @@
 	/* Set preset_lpj to avoid subsequent lpj recalculations */
 	preset_lpj = loops_per_jiffy;
 
-	if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags))
-		flag = cold_boot_flags[cpu];
-	else
-		__WARN();
-
 	if (per_cpu(cold_boot_done, cpu) == false) {
-		ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup),
-					flag);
-		if (ret == 0)
-			release_secondary(cpu);
-		else
-			printk(KERN_DEBUG "Failed to set secondary core boot "
-					  "address\n");
+		release_secondary(cpu);
 		per_cpu(cold_boot_done, cpu) = true;
 	}
 
@@ -224,9 +225,7 @@
 	 * Note that "pen_release" is the hardware CPU ID, whereas
 	 * "cpu" is Linux's internal ID.
 	 */
-	pen_release = cpu_logical_map(cpu);
-	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
-	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+	write_pen_release(cpu_logical_map(cpu));
 
 	/*
 	 * Send the secondary CPU a soft interrupt, thereby causing
@@ -241,8 +240,6 @@
 		if (pen_release == -1)
 			break;
 
-		dmac_inv_range((char *)&pen_release,
-			       (char *)&pen_release + sizeof(pen_release));
 		udelay(10);
 	}
 
@@ -274,6 +271,28 @@
 	set_smp_cross_call(gic_raise_softirq);
 }
 
+static int cold_boot_flags[] __initdata = {
+	0,
+	SCM_FLAG_COLDBOOT_CPU1,
+	SCM_FLAG_COLDBOOT_CPU2,
+	SCM_FLAG_COLDBOOT_CPU3,
+};
+
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
+	int cpu, map;
+	unsigned int flags = 0;
+
+	for_each_present_cpu(cpu) {
+		map = cpu_logical_map(cpu);
+		if (map > ARRAY_SIZE(cold_boot_flags)) {
+			set_cpu_present(cpu, false);
+			__WARN();
+			continue;
+		}
+		flags |= cold_boot_flags[map];
+	}
+
+	if (scm_set_boot_addr(virt_to_phys(msm_secondary_startup), flags))
+		pr_warn("Failed to set CPU boot address\n");
 }
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 10c5445..427e39f 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -487,7 +487,7 @@
 	void __iomem *base_ptr;
 	unsigned int value = 0;
 
-	base_ptr = core1_reset_base();
+	base_ptr = core_reset_base(1);
 	if (!base_ptr)
 		return;
 
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 158dd46..d45043d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -326,6 +326,7 @@
 
 	wait_queue_head_t wait;
 	wait_queue_head_t mode_wait;
+	wait_queue_head_t in_wait;
 	wait_queue_head_t out_wait;
 
 	struct mutex lock;
@@ -1142,6 +1143,7 @@
 
 		mutex_unlock(&audio->in_lock);
 
+		wake_up(&audio->in_wait);
 		dl_reply.valid_frame_info_ptr = cpu_to_be32(0x00000001);
 
 		dl_reply.frame_mode = cpu_to_be32(audio->frame_mode);
@@ -1187,6 +1189,9 @@
 			       rpc_hdr_len);
 
 			break;
+		} else if ((rpc_hdr_len == 0) &&
+				(audio->state == AUDIO_MVS_CLOSED)) {
+			break;
 		} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ) {
 			continue;
 		} else {
@@ -1353,8 +1358,11 @@
 	mutex_lock(&audio->lock);
 	if (audio->state == AUDIO_MVS_STARTED)
 		audio_mvs_stop(audio);
-	audio_mvs_free_buf(audio);
 	audio->state = AUDIO_MVS_CLOSED;
+	msm_rpc_read_wakeup(audio->rpc_endpt);
+	msm_rpc_close(audio->rpc_endpt);
+	audio->task = NULL;
+	audio_mvs_free_buf(audio);
 	mutex_unlock(&audio->lock);
 
 	MM_DBG("Release done\n");
@@ -1443,40 +1451,52 @@
 
 	MM_DBG("\n");
 
-	mutex_lock(&audio->in_lock);
-	if (audio->state == AUDIO_MVS_STARTED) {
-		if (count <= sizeof(struct msm_audio_mvs_frame)) {
-			if (!list_empty(&audio->free_in_queue)) {
-				buf_node =
-					list_first_entry(&audio->free_in_queue,
+	rc = wait_event_interruptible_timeout(audio->in_wait,
+		(!list_empty(&audio->free_in_queue) ||
+		audio->state == AUDIO_MVS_STOPPED), 1 * HZ);
+	if (rc > 0) {
+		mutex_lock(&audio->in_lock);
+		if (audio->state == AUDIO_MVS_STARTED) {
+			if (count <= sizeof(struct msm_audio_mvs_frame)) {
+				if (!list_empty(&audio->free_in_queue)) {
+					buf_node = list_first_entry(
+						&audio->free_in_queue,
 						struct audio_mvs_buf_node,
 						list);
-				list_del(&buf_node->list);
+					list_del(&buf_node->list);
 
-				rc = copy_from_user(&buf_node->frame,
-						    buf,
-						    count);
+					rc = copy_from_user(&buf_node->frame,
+							    buf,
+							    count);
 
-				list_add_tail(&buf_node->list,
-					      &audio->in_queue);
+					list_add_tail(&buf_node->list,
+						      &audio->in_queue);
+				} else {
+					MM_ERR("No free DL buffs\n");
+				}
 			} else {
-				MM_ERR("No free DL buffs\n");
+				MM_ERR("Write count %d > sizeof(frame) %d",
+					count,
+					sizeof(struct msm_audio_mvs_frame));
+
+				rc = -ENOMEM;
 			}
 		} else {
-			MM_ERR("Write count %d < sizeof(frame) %d",
-			       count,
-			       sizeof(struct msm_audio_mvs_frame));
+			MM_ERR("Write performed in invalid state %d\n",
+				audio->state);
 
-			rc = -ENOMEM;
+			rc = -EPERM;
 		}
+		mutex_unlock(&audio->in_lock);
+	} else if (rc == 0) {
+		MM_ERR("%s: No free DL buffs\n", __func__);
+
+		rc = -ETIMEDOUT;
 	} else {
-		MM_ERR("Write performed in invalid state %d\n",
-		       audio->state);
+		MM_ERR("%s: write was interrupted\n", __func__);
 
-		rc = -EPERM;
+		rc = -ERESTARTSYS;
 	}
-	mutex_unlock(&audio->in_lock);
-
 	return rc;
 }
 
@@ -1593,26 +1613,6 @@
 
 	MM_DBG("\n");
 
-	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
-	mutex_init(&audio_mvs_info.lock);
-	mutex_init(&audio_mvs_info.in_lock);
-	mutex_init(&audio_mvs_info.out_lock);
-
-	init_waitqueue_head(&audio_mvs_info.wait);
-	init_waitqueue_head(&audio_mvs_info.mode_wait);
-	init_waitqueue_head(&audio_mvs_info.out_wait);
-
-	INIT_LIST_HEAD(&audio_mvs_info.in_queue);
-	INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
-	INIT_LIST_HEAD(&audio_mvs_info.out_queue);
-	INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
-
-	wake_lock_init(&audio_mvs_info.suspend_lock,
-		       WAKE_LOCK_SUSPEND,
-		       "audio_mvs_suspend");
-	pm_qos_add_request(&audio_mvs_info.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
-
 	audio_mvs_info.rpc_endpt = msm_rpc_connect_compatible(MVS_PROG,
 					MVS_VERS_COMP_VER2,
 					MSM_RPC_UNINTERRUPTIBLE);
@@ -1696,6 +1696,27 @@
 };
 static int __init audio_mvs_init(void)
 {
+	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+	mutex_init(&audio_mvs_info.lock);
+	mutex_init(&audio_mvs_info.in_lock);
+	mutex_init(&audio_mvs_info.out_lock);
+
+	init_waitqueue_head(&audio_mvs_info.wait);
+	init_waitqueue_head(&audio_mvs_info.mode_wait);
+	init_waitqueue_head(&audio_mvs_info.in_wait);
+	init_waitqueue_head(&audio_mvs_info.out_wait);
+
+	INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+	wake_lock_init(&audio_mvs_info.suspend_lock,
+		       WAKE_LOCK_SUSPEND,
+		       "audio_mvs_suspend");
+	pm_qos_add_request(&audio_mvs_info.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
 	return misc_register(&audio_mvs_misc);
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
index 368b8e6..c6c7d23 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.h
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
@@ -24,7 +24,7 @@
 #include <linux/cdev.h>
 #include <linux/list.h>
 #include <linux/hash.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/msm_smd.h>
 #include <mach/ion.h>
 #include "adsprpc_shared.h"
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
index c19fd85..63b3064 100644
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -26,7 +26,7 @@
 #include <mach/msm_hdmi_audio.h>
 #include <mach/audio_dma_msm8k.h>
 #include <sound/dai.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
 
 #define DMA_ALLOC_BUF_SZ		(SZ_4K * 16)
 
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index d7de50e..9dd66e1 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -26,7 +26,7 @@
 #include <linux/delay.h>
 #include <mach/msm_smd.h>
 #include <mach/qdsp6v2/apr.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
 
 #define TIMEOUT_MS 1000
 
@@ -79,6 +79,10 @@
 			bus_bw_resp_received = 1;
 			wake_up(&bus_bw_req_wait);
 			break;
+		case ADSP_CMD_SET_DTS_MODEL_ID:
+			pr_debug("ADSP_CMD_SET_DTS_MODEL_ID status[0x%x]\n",
+					payload1[1]);
+			break;
 		default:
 			pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
 					payload1[0], payload1[1]);
@@ -382,6 +386,35 @@
 	return count;
 }
 
+uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id)
+{
+	struct adsp_dts_modelid payload;
+	int rc = 0;
+	pr_debug("core_set_dts_model_id(): Enter\n");
+	core_open();
+	if (core_handle_q) {
+		payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		payload.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(uint32_t)+id_size);
+		payload.hdr.src_port = 0;
+		payload.hdr.dest_port = 0;
+		payload.hdr.token = 0;
+		payload.hdr.opcode = ADSP_CMD_SET_DTS_MODEL_ID;
+		payload.model_ID_size = id_size;
+		memcpy(payload.model_ID, id, id_size+1);
+		pr_debug("Send DTS sec opcode=%x modelID = %s, size=%d\n",
+			payload.hdr.opcode, (char *)payload.model_ID,
+			payload.model_ID_size);
+		rc = apr_send_pkt(core_handle_q, (uint32_t *)&payload);
+		if (rc < 0)
+			pr_err("%s: SET_DTS_DTS_MODEL_ID failed op[0x%x]rc[%d]\n",
+				__func__, payload.hdr.opcode, rc);
+	}
+	pr_debug("core_set_dts_model_id(): Exit\n");
+	return rc;
+}
+
 static const struct file_operations apr_debug_fops = {
 	.write = apr_debug_write,
 	.open = apr_debug_open,
diff --git a/arch/arm/mach-msm/qdsp6v2/q6voice.c b/arch/arm/mach-msm/qdsp6v2/q6voice.c
index 12a02c5..7464ed7 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6voice.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6voice.c
@@ -30,7 +30,7 @@
 #include <mach/qdsp6v2/rtac.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
 
 
 #define TIMEOUT_MS 3000
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 5883b0c..2189747 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -36,6 +36,7 @@
 #include <mach/scm.h>
 #include "msm_watchdog.h"
 #include "timer.h"
+#include "wdog_debug.h"
 
 #define WDT0_RST	0x38
 #define WDT0_EN		0x40
@@ -250,8 +251,11 @@
 		__raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
 		__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
 		__raw_writel(1, msm_tmr0_base + WDT0_EN);
-	} else
+	} else {
+		/* Needed for 8974: Reset GCC_WDOG_DEBUG register */
+		msm_disable_wdog_debug();
 		__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
+	}
 
 	mdelay(10000);
 	printk(KERN_ERR "Restarting has failed\n");
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index 8fe3571..c5c01c2 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -325,3 +325,32 @@
 {
 	return &config;
 }
+
+struct vreg_config *get_config_8960_pm8917(void)
+{
+	int i;
+
+	/*
+	 * PM8917 regulators L24, L25, L26, L27, and L28 require CXO to be ON
+	 * while they are enabled.  These same regulators on PM8921 do not
+	 * require CXO to be ON.  Therefore, set the require_cxo flag for these
+	 * regulators only when using PM8917.
+	 *
+	 * Do not apply the workaround to L24 (VDD_MX) because it is always on
+	 * and using the TCXO workaround with it would result in additional
+	 * latency during every Krait upscaling event.
+	 */
+	for (i = 0; i < ARRAY_SIZE(vregs); i++) {
+		switch (vregs[i].id) {
+		case RPM_VREG_ID_PM8921_L25:
+		case RPM_VREG_ID_PM8921_L26:
+		case RPM_VREG_ID_PM8921_L27:
+		case RPM_VREG_ID_PM8921_L28:
+			vregs[i].requires_cxo = true;
+		default:
+			break;
+		}
+	}
+
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index d55bd73..703335f 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -158,11 +158,16 @@
 #if defined(CONFIG_MSM_RPM_REGULATOR) && \
 	(defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064))
 struct vreg_config *get_config_8960(void);
+struct vreg_config *get_config_8960_pm8917(void);
 #else
 static inline struct vreg_config *get_config_8960(void)
 {
 	return NULL;
 }
+static inline struct vreg_config *get_config_8960_pm8917(void)
+{
+	return NULL;
+}
 #endif
 
 #if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM9615)
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index a8af9e7..d1c61fe 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -112,7 +112,7 @@
 	PARAM(HEAD_ROOM,       1,  0,  0,  1, "hr",   0, 0x7FFFFFFF, "qcom,init-head-room"),
 	PARAM(QUIET_MODE,      0,  1,  0,  0, "qm",   0, 2,          "qcom,init-quiet-mode"),
 	PARAM(FREQ_REASON,     0,  1,  0,  1, "resn", 0, 8,          "qcom,init-freq-reason"),
-	PARAM(CORNER,          0,  1,  0,  0, "corn", 0, 6,          "qcom,init-voltage-corner"),
+	PARAM(CORNER,          1,  1,  0,  0, "corn", 0, 6,          "qcom,init-voltage-corner"),
 	PARAM(BYPASS,          1,  0,  0,  0, "bypa", 0, 1,          "qcom,init-disallow-bypass"),
 };
 
@@ -1037,6 +1037,19 @@
 	.enable_time		= rpm_vreg_enable_time,
 };
 
+static struct regulator_ops ldo_corner_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage_corner,
+	.get_voltage		= rpm_vreg_get_voltage_corner,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
 static struct regulator_ops smps_ops = {
 	.enable			= rpm_vreg_enable,
 	.disable		= rpm_vreg_disable,
@@ -1194,11 +1207,14 @@
 
 	/*
 	 * Switch to voltage corner regulator ops if qcom,use-voltage-corner
-	 * is specified in the device node (SMPS only).
+	 * is specified in the device node (SMPS and LDO only).
 	 */
-	if (of_find_property(node, "qcom,use-voltage-corner", NULL)
-	    && regulator_type == RPM_REGULATOR_SMD_TYPE_SMPS)
-		reg->rdesc.ops = &smps_corner_ops;
+	if (of_property_read_bool(node, "qcom,use-voltage-corner")) {
+		if (regulator_type == RPM_REGULATOR_SMD_TYPE_SMPS)
+			reg->rdesc.ops = &smps_corner_ops;
+		else if (regulator_type == RPM_REGULATOR_SMD_TYPE_LDO)
+			reg->rdesc.ops = &ldo_corner_ops;
+	}
 
 	if (regulator_type == RPM_REGULATOR_SMD_TYPE_VS)
 		reg->rdesc.n_voltages = 0;
@@ -1286,7 +1302,7 @@
 		}
 	}
 
-	of_property_read_u32(node, "qcom,system_load", &reg->system_load);
+	of_property_read_u32(node, "qcom,system-load", &reg->system_load);
 
 	rpm_vreg_lock(rpm_vreg);
 	list_add(&reg->list, &rpm_vreg->reg_list);
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 424a4fe..01543a2 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -63,6 +63,7 @@
 	[RPM_VREG_VERSION_9615] = get_config_9615,
 	[RPM_VREG_VERSION_8930] = get_config_8930,
 	[RPM_VREG_VERSION_8930_PM8917] = get_config_8930_pm8917,
+	[RPM_VREG_VERSION_8960_PM8917] = get_config_8960_pm8917,
 };
 
 static struct rpm_regulator_consumer_mapping *consumer_map;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a9d1ed8..7c31e76 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -149,8 +149,6 @@
 	uint32_t id_ack;
 };
 
-static int irq_process;
-
 LIST_HEAD(msm_rpm_ack_list);
 
 static void msm_rpm_notify_sleep_chain(struct rpm_message_header *hdr,
@@ -518,20 +516,18 @@
 	uint32_t msg_id;
 	int errno;
 	char buf[MAX_ERR_BUFFER_SIZE] = {0};
-	unsigned long flags;
 
-	while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
-		spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
+	if (!spin_trylock(&msm_rpm_data.smd_lock_read))
+		return;
+	while (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
 		if (msm_rpm_read_smd_data(buf)) {
-			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read,
-					flags);
 			break;
 		}
 		msg_id = msm_rpm_get_msg_id_from_ack(buf);
 		errno = msm_rpm_get_error_from_ack(buf);
 		msm_rpm_process_ack(msg_id, errno);
-		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
 	}
+	spin_unlock(&msm_rpm_data.smd_lock_read);
 }
 
 #define DEBUG_PRINT_BUFFER_SIZE 512
@@ -783,7 +779,14 @@
 
 int msm_rpm_send_request(struct msm_rpm_request *handle)
 {
-	return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false);
+	int ret;
+	static DEFINE_MUTEX(send_mtx);
+
+	mutex_lock(&send_mtx);
+	ret = msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false);
+	mutex_unlock(&send_mtx);
+
+	return ret;
 }
 EXPORT_SYMBOL(msm_rpm_send_request);
 
@@ -837,7 +840,6 @@
 		return 0;
 
 	spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
-	irq_process = true;
 
 	elem = msm_rpm_get_entry_from_msg_id(msg_id);
 
@@ -868,7 +870,6 @@
 	rc = elem->errno;
 	msm_rpm_free_list_entry(elem);
 wait_ack_cleanup:
-	irq_process = false;
 	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
 	return rc;
 }
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 2a835f7..dfed3aa 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -945,7 +945,8 @@
 					irqs_detectable, gpio_detectable))
 			continue;
 
-		if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+		if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+			|| (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
 			if (!cpu && msm_rpm_local_request_is_outstanding())
 					break;
 
@@ -1131,7 +1132,8 @@
 static int __init msm_rpmrs_l2_init(void)
 {
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab()) {
+	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab() ||
+						cpu_is_apq8064ab()) {
 
 		msm_pm_set_l2_flush_flag(0);
 
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index dd24e20..8da1d75 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -25,8 +25,29 @@
 	PAS_VIDC,
 };
 
+#ifdef CONFIG_MSM_PIL
 extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
 extern int pas_auth_and_reset(enum pas_id id);
 extern int pas_shutdown(enum pas_id id);
 extern int pas_supported(enum pas_id id);
+#else
+static inline int pas_init_image(enum pas_id id, const u8 *metadata,
+		size_t size)
+{
+	return 0;
+}
+static inline int pas_auth_and_reset(enum pas_id id)
+{
+	return 0;
+}
+static inline int pas_shutdown(enum pas_id id)
+{
+	return 0;
+}
+static inline int pas_supported(enum pas_id id)
+{
+	return 0;
+}
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e33f87b..c1e2421 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -35,6 +35,7 @@
 #include <linux/wakelock.h>
 #include <linux/notifier.h>
 #include <linux/sort.h>
+#include <linux/suspend.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
@@ -553,6 +554,26 @@
 	}
 }
 
+static int smsm_pm_notifier(struct notifier_block *nb,
+				unsigned long event, void *unused)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		smsm_change_state(SMSM_APPS_STATE, SMSM_PROC_AWAKE, 0);
+		break;
+
+	case PM_POST_SUSPEND:
+		smsm_change_state(SMSM_APPS_STATE, 0, SMSM_PROC_AWAKE);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block smsm_pm_nb = {
+	.notifier_call = smsm_pm_notifier,
+	.priority = 0,
+};
+
 void smd_diag(void)
 {
 	char *x;
@@ -2545,6 +2566,12 @@
 		return i;
 
 	wmb();
+
+	smsm_pm_notifier(&smsm_pm_nb, PM_POST_SUSPEND, NULL);
+	i = register_pm_notifier(&smsm_pm_nb);
+	if (i)
+		pr_err("%s: power state notif error %d\n", __func__, i);
+
 	return 0;
 }
 
@@ -3513,9 +3540,10 @@
 static struct restart_notifier_block restart_notifiers[] = {
 	{SMD_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
 	{SMD_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
-	{SMD_WCNSS, "riva", .nb.notifier_call = restart_notifier_cb},
+	{SMD_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
 	{SMD_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
 	{SMD_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+	{SMD_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
 };
 
 static int restart_notifier_cb(struct notifier_block *this,
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
index 983d0c1..68c3dd3 100644
--- a/arch/arm/mach-msm/smd_rpcrouter.c
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -2421,6 +2421,7 @@
 {
 	struct rpcrouter_xprt_info *xprt_info;
 	struct rpcrouter_xprt_work *xprt_work;
+	unsigned long flags;
 
 	/* Workqueue is created in init function which works for all existing
 	 * clients.  If this fails in the future, then it will need to be
@@ -2452,11 +2453,13 @@
 
 	xprt_info = xprt->priv;
 	if (xprt_info) {
+		spin_lock_irqsave(&xprt_info->lock, flags);
 		/* Check read_avail even for OPEN event to handle missed
 		   DATA events while processing the OPEN event*/
 		if (xprt->read_avail() >= xprt_info->need_len)
 			wake_lock(&xprt_info->wakelock);
 		wake_up(&xprt_info->read_wait);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
 	}
 }
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 86de130..ac077e9 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -286,6 +286,9 @@
 	/* 8092 IDs */
 	[146] = MSM_CPU_8092,
 
+	/* 8064AB IDs */
+	[153] = MSM_CPU_8064AB,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 1eab9bf..f0d3d06 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -179,7 +179,7 @@
 	}
 }
 
-static inline uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+uint32_t msm_spm_drv_get_sts_curr_pmic_data(
 		struct msm_spm_driver_data *dev)
 {
 	if (dev->major == SAW2_MAJOR_2) {
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index e81e335..09ee26a 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -141,6 +141,13 @@
 int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
 
 /**
+ * msm_spm_get_vdd(): Get core voltage
+ * @cpu: core id
+ * @return: Returns encoded PMIC data.
+ */
+unsigned int msm_spm_get_vdd(unsigned int cpu);
+
+/**
  * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
  * @cpu: core id
  */
@@ -239,6 +246,11 @@
 	return -ENOSYS;
 }
 
+static inline unsigned int msm_spm_get_vdd(unsigned int cpu)
+{
+	return 0;
+}
+
 static inline void msm_spm_reinit(void)
 {
 	/* empty */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index b87b0f1..2cbed94 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -75,6 +75,15 @@
 }
 EXPORT_SYMBOL(msm_spm_set_vdd);
 
+unsigned int msm_spm_get_vdd(unsigned int cpu)
+{
+	struct msm_spm_device *dev;
+
+	dev = &per_cpu(msm_cpu_spm_device, cpu);
+	return msm_spm_drv_get_sts_curr_pmic_data(&dev->reg_data);
+}
+EXPORT_SYMBOL(msm_spm_get_vdd);
+
 static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
 		unsigned int mode, bool notify_rpm)
 {
@@ -159,7 +168,8 @@
 	reg = saw_bases[cpu];
 
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab()) {
+	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab() ||
+						cpu_is_apq8064ab()) {
 		val = 0xA4;
 		reg += 0x14;
 		timeout = 512;
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
index f272adb..4cdfd33 100644
--- a/arch/arm/mach-msm/spm_driver.h
+++ b/arch/arm/mach-msm/spm_driver.h
@@ -35,6 +35,8 @@
 		uint32_t addr);
 int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
 		unsigned int vlevel);
+uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+		struct msm_spm_driver_data *dev);
 int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
 		uint8_t *cmd, uint32_t *offset);
 void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev);
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 1305bd1..02ba5ea 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -159,6 +159,41 @@
 }
 
 /**
+ * sysmon_send_shutdown() - send shutdown command to a
+ * subsystem.
+ * @dest_ss:	ID of subsystem to send to.
+ *
+ * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if
+ * the SMD transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds with something unexpected.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_send_shutdown(enum subsys_id dest_ss)
+{
+	struct sysmon_subsys *ss = &subsys[dest_ss];
+	const char tx_buf[] = "system:shutdown";
+	const char expect[] = "system:ack";
+	size_t prefix_len = ARRAY_SIZE(expect) - 1;
+	int ret;
+
+	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS)
+		return -EINVAL;
+
+	mutex_lock(&ss->lock);
+	ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf));
+	if (ret)
+		goto out;
+
+	if (strncmp(ss->rx_buf, expect, prefix_len))
+		ret = -ENOSYS;
+out:
+	mutex_unlock(&ss->lock);
+	return ret;
+}
+
+/**
  * sysmon_get_reason() - Retrieve failure reason from a subsystem.
  * @dest_ss:	ID of subsystem to query
  * @buf:	Caller-allocated buffer for the returned NUL-terminated reason
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
index 77c3329..8c2f6ea 100644
--- a/arch/arm/mach-msm/sysmon.h
+++ b/arch/arm/mach-msm/sysmon.h
@@ -38,6 +38,7 @@
 int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
 		      enum subsys_notif_type notif);
 int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
+int sysmon_send_shutdown(enum subsys_id dest_ss);
 #else
 static inline int sysmon_send_event(enum subsys_id dest_ss,
 				    const char *event_ss,
@@ -50,6 +51,10 @@
 {
 	return 0;
 }
+static inline int sysmon_send_shutdown(enum subsys_id dest_ss)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 668f4cc..b361d9d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -966,7 +966,7 @@
 
 	if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
 	    cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
-	    cpu_is_msm8960ab())
+	    cpu_is_msm8960ab() || cpu_is_apq8064ab())
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 
 	if (__get_cpu_var(first_boot)) {
@@ -1064,7 +1064,7 @@
 		dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 	} else if (cpu_is_msm8960() || cpu_is_apq8064() || cpu_is_msm8930() ||
 		   cpu_is_msm8930aa() || cpu_is_msm8627() ||
-		   cpu_is_msm8960ab()) {
+		   cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
 		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
 		dgt->freq = 6750000;
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
@@ -1127,7 +1127,7 @@
 		if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
 		    cpu_is_msm8930() || cpu_is_msm9615() || cpu_is_msm8625() ||
 		    cpu_is_msm8627() || cpu_is_msm8930aa() ||
-		    cpu_is_msm8960ab()) {
+		    cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
 			clock->percpu_evt = alloc_percpu(struct clock_event_device *);
 			if (!clock->percpu_evt) {
 				pr_err("msm_timer_init: memory allocation "
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
deleted file mode 100644
index f014df9..0000000
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/err.h>
-#include <asm/mach-types.h>
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-#include <mach/peripheral-loader.h>
-#include "smd_private.h"
-#include "ramdump.h"
-
-#define MODULE_NAME			"wcnss_8960"
-#define MAX_BUF_SIZE			0x51
-
-
-
-static struct delayed_work cancel_vote_work;
-static void *riva_ramdump_dev;
-static int riva_crash;
-static int ss_restart_inprogress;
-static int enable_riva_ssr;
-static struct subsys_device *riva_8960_dev;
-
-static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
-					uint32_t new_state)
-{
-	char *smem_reset_reason;
-	char buffer[MAX_BUF_SIZE];
-	unsigned smem_reset_size;
-	unsigned size;
-
-	riva_crash = true;
-
-	pr_err("%s: smsm state changed\n", MODULE_NAME);
-
-	if (!(new_state & SMSM_RESET))
-		return;
-
-	if (ss_restart_inprogress) {
-		pr_err("%s: Ignoring smsm reset req, restart in progress\n",
-						MODULE_NAME);
-		return;
-	}
-
-	if (!enable_riva_ssr)
-		panic(MODULE_NAME ": SMSM reset request received from Riva");
-
-	smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
-			&smem_reset_size);
-
-	if (!smem_reset_reason || !smem_reset_size) {
-		pr_err("%s: wcnss subsystem failure reason: %s\n",
-				__func__, "(unknown, smem_get_entry failed)");
-	} else if (!smem_reset_reason[0]) {
-		pr_err("%s: wcnss subsystem failure reason: %s\n",
-				__func__, "(unknown, init string found)");
-	} else {
-		size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
-			(MAX_BUF_SIZE - 1);
-		memcpy(buffer, smem_reset_reason, size);
-		buffer[size] = '\0';
-		pr_err("%s: wcnss subsystem failure reason: %s\n",
-				__func__, buffer);
-		memset(smem_reset_reason, 0, smem_reset_size);
-		wmb();
-	}
-
-	ss_restart_inprogress = true;
-	subsystem_restart_dev(riva_8960_dev);
-}
-
-static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
-{
-	riva_crash = true;
-
-	if (ss_restart_inprogress) {
-		pr_err("%s: Ignoring riva bite irq, restart in progress\n",
-						MODULE_NAME);
-		return IRQ_HANDLED;
-	}
-
-	if (!enable_riva_ssr)
-		panic(MODULE_NAME ": Watchdog bite received from Riva");
-
-	ss_restart_inprogress = true;
-	subsystem_restart_dev(riva_8960_dev);
-
-	return IRQ_HANDLED;
-}
-
-/* SMSM reset Riva */
-static void smsm_riva_reset(void)
-{
-	/* per SS reset request bit is not available now,
-	 * all SS host modules are setting this bit
-	 * This is still under discussion*/
-	smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
-}
-
-static void riva_post_bootup(struct work_struct *work)
-{
-	struct platform_device *pdev = wcnss_get_platform_device();
-	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-
-	pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
-
-	wcnss_wlan_power(&pdev->dev, pwlanconfig,
-		WCNSS_WLAN_SWITCH_OFF);
-}
-
-/* Subsystem handlers */
-static int riva_shutdown(const struct subsys_desc *subsys)
-{
-	pil_force_shutdown("wcnss");
-	flush_delayed_work(&cancel_vote_work);
-	wcnss_flush_delayed_boot_votes();
-	disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
-
-	return 0;
-}
-
-static int riva_powerup(const struct subsys_desc *subsys)
-{
-	struct platform_device *pdev = wcnss_get_platform_device();
-	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-	int    ret = -1;
-
-	if (pdev && pwlanconfig)
-		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
-					WCNSS_WLAN_SWITCH_ON);
-	/* delay PIL operation, this SSR may be happening soon after kernel
-	 * resumes because of a SMSM RESET by Riva when APPS was suspended.
-	 * PIL fails to locate the images without this delay */
-	if (!ret) {
-		msleep(1000);
-		pil_force_boot("wcnss");
-	}
-	ss_restart_inprogress = false;
-	enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
-	schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
-
-	return ret;
-}
-
-/* 5MB RAM segments for Riva SS */
-static struct ramdump_segment riva_segments[] = {{0x8f200000,
-						0x8f700000 - 0x8f200000} };
-
-static int riva_ramdump(int enable, const struct subsys_desc *subsys)
-{
-	pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
-	if (enable)
-		return do_ramdump(riva_ramdump_dev,
-				riva_segments,
-				ARRAY_SIZE(riva_segments));
-	else
-		return 0;
-}
-
-/* Riva crash handler */
-static void riva_crash_shutdown(const struct subsys_desc *subsys)
-{
-	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
-	if (riva_crash != true)
-		smsm_riva_reset();
-}
-
-static struct subsys_desc riva_8960 = {
-	.name = "riva",
-	.shutdown = riva_shutdown,
-	.powerup = riva_powerup,
-	.ramdump = riva_ramdump,
-	.crash_shutdown = riva_crash_shutdown
-};
-
-static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
-{
-	int ret;
-
-	ret = param_set_int(val, kp);
-	if (ret)
-		return ret;
-
-	if (enable_riva_ssr)
-		pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
-
-	return 0;
-}
-
-module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
-			&enable_riva_ssr, S_IRUGO | S_IWUSR);
-
-static int __init riva_restart_init(void)
-{
-	riva_8960_dev = subsys_register(&riva_8960);
-	if (IS_ERR(riva_8960_dev))
-		return PTR_ERR(riva_8960_dev);
-	return 0;
-}
-
-static int __init riva_ssr_module_init(void)
-{
-	int ret;
-
-	if (machine_is_mpq8064_hrd()) {
-		pr_err("Riva not supported on this target\n");
-		return 0;
-	}
-
-	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
-					smsm_state_cb_hdlr, 0);
-	if (ret < 0) {
-		pr_err("%s: Unable to register smsm callback for Riva Reset! %d\n",
-				MODULE_NAME, ret);
-		goto out;
-	}
-	ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
-			riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
-				"riva_wdog", NULL);
-
-	if (ret < 0) {
-		pr_err("%s: Unable to register for Riva bite interrupt (%d)\n",
-				MODULE_NAME, ret);
-		goto out;
-	}
-	ret = riva_restart_init();
-	if (ret < 0) {
-		pr_err("%s: Unable to register with ssr. (%d)\n",
-				MODULE_NAME, ret);
-		goto out;
-	}
-	riva_ramdump_dev = create_ramdump_device("riva");
-	if (!riva_ramdump_dev) {
-		pr_err("%s: Unable to create ramdump device.\n",
-				MODULE_NAME);
-		ret = -ENOMEM;
-		goto out;
-	}
-	INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
-
-	pr_info("%s: module initialized\n", MODULE_NAME);
-out:
-	return ret;
-}
-
-static void __exit riva_ssr_module_exit(void)
-{
-	if (machine_is_mpq8064_hrd())
-		return;
-	subsys_unregister(riva_8960_dev);
-	free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
-}
-
-module_init(riva_ssr_module_init);
-module_exit(riva_ssr_module_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wcnss-ssr-8974.c b/arch/arm/mach-msm/wcnss-ssr-8974.c
index d8745fc..b837efc 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8974.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8974.c
@@ -25,7 +25,7 @@
 static int wcnss_crash;
 static struct subsys_device *wcnss_ssr_dev;
 
-#define WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ		231
+#define WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ		181
 
 static void log_wcnss_sfr(void)
 {
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
new file mode 100644
index 0000000..82800cf
--- /dev/null
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <mach/scm.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "wdog_debug"
+#define WDOG_DEBUG_EN 17
+#define GCC_WDOG_DEBUG_OFFSET 0x780
+
+struct msm_wdog_debug_data {
+	unsigned int __iomem phys_base;
+	size_t size;
+	void __iomem *base;
+	struct device *dev;
+};
+
+static struct msm_wdog_debug_data *wdog_data;
+
+void msm_disable_wdog_debug(void)
+{
+	unsigned long int value;
+
+	if (wdog_data == NULL)
+		return;
+	value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+	value &= ~BIT(WDOG_DEBUG_EN);
+	writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+}
+EXPORT_SYMBOL(msm_disable_wdog_debug);
+
+void msm_enable_wdog_debug(void)
+{
+	unsigned long int value;
+
+	if (wdog_data == NULL)
+		return;
+	value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+	value |= BIT(WDOG_DEBUG_EN);
+	writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+}
+EXPORT_SYMBOL(msm_enable_wdog_debug);
+
+static int __devexit msm_wdog_debug_remove(struct platform_device *pdev)
+{
+	kfree(wdog_data);
+	wdog_data = NULL;
+	pr_info("MSM wdog_debug Exit - Deactivated\n");
+	return 0;
+}
+
+static int __devinit msm_wdog_debug_dt_to_pdata(struct platform_device *pdev,
+					struct msm_wdog_debug_data *pdata)
+{
+	struct resource *wdog_resource;
+
+	wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!wdog_resource) {
+		dev_err(&pdev->dev, \
+		"%s cannot allocate resource for wdog_debug\n", \
+		 __func__);
+		return -ENXIO;
+	}
+	pdata->size = resource_size(wdog_resource);
+	pdata->phys_base = wdog_resource->start;
+	if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base,
+					pdata->size, "msm-wdog-debug")))) {
+		dev_err(&pdev->dev, "%s cannot reserve wdog_debug region\n",
+								__func__);
+		return -ENXIO;
+	}
+	pdata->base  = devm_ioremap(&pdev->dev, pdata->phys_base,
+							pdata->size);
+	if (!pdata->base) {
+		dev_err(&pdev->dev, "%s cannot map wdog register space\n",
+				__func__);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int __devinit msm_wdog_debug_probe(struct platform_device *pdev)
+{
+	int ret;
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+	wdog_data = kzalloc(sizeof(struct msm_wdog_debug_data), GFP_KERNEL);
+	if (!wdog_data)
+		return -ENOMEM;
+	ret = msm_wdog_debug_dt_to_pdata(pdev, wdog_data);
+	if (ret)
+		goto err;
+	wdog_data->dev = &pdev->dev;
+	platform_set_drvdata(pdev, wdog_data);
+	msm_enable_wdog_debug();
+	return 0;
+err:
+	kzfree(wdog_data);
+	wdog_data = NULL;
+	return ret;
+}
+
+static struct of_device_id msm_wdog_debug_match_table[] = {
+	{ .compatible = "qcom,msm-wdog-debug" },
+	{}
+};
+
+static struct platform_driver msm_wdog_debug_driver = {
+	.probe = msm_wdog_debug_probe,
+	.remove = msm_wdog_debug_remove,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_wdog_debug_match_table,
+	},
+};
+
+static int __devinit wdog_debug_init(void)
+{
+	return platform_driver_register(&msm_wdog_debug_driver);
+}
+module_init(wdog_debug_init);
+
+static void __exit wdog_debug_exit(void)
+{
+	platform_driver_unregister(&msm_wdog_debug_driver);
+}
+module_exit(wdog_debug_exit);
+
+MODULE_DESCRIPTION("MSM Driver to disable debug Image");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wdog_debug.h b/arch/arm/mach-msm/wdog_debug.h
new file mode 100644
index 0000000..920aa89
--- /dev/null
+++ b/arch/arm/mach-msm/wdog_debug.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WDOG_DEBUG_H
+#define __WDOG_DEBUG_H
+
+#ifdef CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL
+void msm_enable_wdog_debug(void);
+void msm_disable_wdog_debug(void);
+#else
+void msm_enable_wdog_debug(void) { }
+void msm_disable_wdog_debug(void) { }
+#endif
+
+#endif
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 47dab27..ba93e68 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -393,6 +393,16 @@
 	.size	__v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
 
 	/*
+	 * Qualcomm Inc. Krait processors.
+	 */
+	.type	__krait_proc_info, #object
+__krait_proc_info:
+	.long	0x510f0400		@ Required ID value
+	.long	0xff0ffc00		@ Mask for ID
+	__v7_proc __v7_setup, hwcaps = HWCAP_IDIV
+	.size	__krait_proc_info, . - __krait_proc_info
+
+	/*
 	 * Match any ARMv7 processor core.
 	 */
 	.type	__v7_proc_info, #object
diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c
index 6253605..acff5a5 100644
--- a/drivers/bluetooth/hci_ibs.c
+++ b/drivers/bluetooth/hci_ibs.c
@@ -254,13 +254,14 @@
 	struct ibs_struct *ibs = container_of(work, struct ibs_struct,
 					ws_awake_device);
 	struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+	unsigned long flags;
 
 	BT_DBG(" %p ", hu);
 
 	/* Vote for serial clock */
 	ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
 
-	spin_lock(&ibs->hci_ibs_lock);
+	spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
 
 	/* send wake indication to device */
 	if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
@@ -271,7 +272,8 @@
 	/* start retransmit timer */
 	mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
 
-	spin_unlock(&ibs->hci_ibs_lock);
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
 }
 
 static void ibs_wq_awake_rx(struct work_struct *work)
@@ -279,12 +281,14 @@
 	struct ibs_struct *ibs = container_of(work, struct ibs_struct,
 					ws_awake_rx);
 	struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+	unsigned long flags;
 
 	BT_DBG(" %p ", hu);
 
 	ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
 
-	spin_lock(&ibs->hci_ibs_lock);
+	spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
 	ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
 	/* Always acknowledge device wake up,
 	 * sending IBS message doesn't count as TX ON
@@ -294,7 +298,8 @@
 
 	ibs->ibs_sent_wacks++; /* debug */
 
-	spin_unlock(&ibs->hci_ibs_lock);
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
 	/* actually send the packets */
 	hci_uart_tx_wakeup(hu);
 
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index ea75ffd..6ecc970 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -2,4 +2,4 @@
 obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
 obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
 obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
-diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o
+diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
new file mode 100644
index 0000000..ed0f08e
--- /dev/null
+++ b/drivers/char/diag/diag_debugfs.c
@@ -0,0 +1,305 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+
+#define DEBUG_BUF_SIZE	4096
+static struct dentry *diag_dbgfs_dent;
+static int diag_dbgfs_table_index;
+
+static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
+				      size_t count, loff_t *ppos)
+{
+	char *buf;
+	int ret;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf) {
+		pr_err("diag: %s, Error allocating memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+		"modem ch: 0x%x\n"
+		"lpass ch: 0x%x\n"
+		"riva ch: 0x%x\n"
+		"dci ch: 0x%x\n"
+		"modem cntl_ch: 0x%x\n"
+		"lpass cntl_ch: 0x%x\n"
+		"riva cntl_ch: 0x%x\n"
+		"CPU Tools id: %d\n"
+		"Apps only: %d\n"
+		"Apps master: %d\n"
+		"Check Polling Response: %d\n"
+		"polling_reg_flag: %d\n"
+		"uses device tree: %d\n"
+		"in_busy_1: %d\n"
+		"in_busy_2: %d\n"
+		"in_busy_lpass_1: %d\n"
+		"in_busy_lpass_2: %d\n"
+		"in_busy_wcnss_1: %d\n"
+		"in_busy_wcnss_2: %d\n"
+		"in_busy_dci: %d\n"
+		"logging_mode: %d\n",
+		(unsigned int)driver->ch,
+		(unsigned int)driver->chlpass,
+		(unsigned int)driver->ch_wcnss,
+		(unsigned int)driver->ch_dci,
+		(unsigned int)driver->ch_cntl,
+		(unsigned int)driver->chlpass_cntl,
+		(unsigned int)driver->ch_wcnss_cntl,
+		chk_config_get_id(),
+		chk_apps_only(),
+		chk_apps_master(),
+		chk_polling_response(),
+		driver->polling_reg_flag,
+		driver->use_device_tree,
+		driver->in_busy_1,
+		driver->in_busy_2,
+		driver->in_busy_lpass_1,
+		driver->in_busy_lpass_2,
+		driver->in_busy_wcnss_1,
+		driver->in_busy_wcnss_2,
+		driver->in_busy_dci,
+		driver->logging_mode);
+
+#ifdef CONFIG_DIAG_OVER_USB
+	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+		"usb_connected: %d\n",
+		driver->usb_connected);
+#endif
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t diag_dbgfs_read_workpending(struct file *file,
+				char __user *ubuf, size_t count, loff_t *ppos)
+{
+	char *buf;
+	int ret;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf) {
+		pr_err("diag: %s, Error allocating memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+		"Pending status for work_stucts:\n"
+		"diag_drain_work: %d\n"
+		"diag_read_smd_work: %d\n"
+		"diag_read_smd_cntl_work: %d\n"
+		"diag_read_smd_lpass_work: %d\n"
+		"diag_read_smd_lpass_cntl_work: %d\n"
+		"diag_read_smd_wcnss_work: %d\n"
+		"diag_read_smd_wcnss_cntl_work: %d\n"
+		"diag_modem_mask_update_work: %d\n"
+		"diag_lpass_mask_update_work: %d\n"
+		"diag_wcnss_mask_update_work: %d\n"
+		"diag_read_smd_dci_work: %d\n",
+		work_pending(&(driver->diag_drain_work)),
+		work_pending(&(driver->diag_read_smd_work)),
+		work_pending(&(driver->diag_read_smd_cntl_work)),
+		work_pending(&(driver->diag_read_smd_lpass_work)),
+		work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
+		work_pending(&(driver->diag_read_smd_wcnss_work)),
+		work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
+		work_pending(&(driver->diag_modem_mask_update_work)),
+		work_pending(&(driver->diag_lpass_mask_update_work)),
+		work_pending(&(driver->diag_wcnss_mask_update_work)),
+		work_pending(&(driver->diag_read_smd_dci_work)));
+
+#ifdef CONFIG_DIAG_OVER_USB
+	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+		"diag_proc_hdlc_work: %d\n"
+		"diag_read_work: %d\n",
+		work_pending(&(driver->diag_proc_hdlc_work)),
+		work_pending(&(driver->diag_read_work)));
+#endif
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
+				     size_t count, loff_t *ppos)
+{
+	char *buf;
+	int ret = 0;
+	int i;
+	int bytes_remaining;
+	int bytes_in_buffer = 0;
+	int bytes_written;
+	int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+
+	if (diag_dbgfs_table_index >= diag_max_reg) {
+		/* Done. Reset to prepare for future requests */
+		diag_dbgfs_table_index = 0;
+		return 0;
+	}
+
+	buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
+	if (!buf) {
+		pr_err("diag: %s, Error allocating memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	bytes_remaining = buf_size;
+	for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
+		/* Do not process empty entries in the table */
+		if (driver->table[i].process_id == 0)
+			continue;
+
+		bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
+			"i: %3d, cmd_code: %4x, subsys_id: %4x, "
+			"client: %2d, cmd_code_lo: %4x, "
+			"cmd_code_hi: %4x, process_id: %5d\n",
+			i,
+			driver->table[i].cmd_code,
+			driver->table[i].subsys_id,
+			driver->table[i].client_id,
+			driver->table[i].cmd_code_lo,
+			driver->table[i].cmd_code_hi,
+			driver->table[i].process_id);
+
+		bytes_in_buffer += bytes_written;
+
+		/* Check if there is room to add another table entry */
+		bytes_remaining = buf_size - bytes_in_buffer;
+		if (bytes_remaining < bytes_written)
+			break;
+	}
+	diag_dbgfs_table_index = i;
+
+	*ppos = 0;
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
+
+	kfree(buf);
+	return ret;
+}
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
+				    size_t count, loff_t *ppos)
+{
+	char *buf;
+	int ret;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf) {
+		pr_err("diag: %s, Error allocating memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+		"hsic ch: %d\n"
+		"hsic_inited: %d\n"
+		"hsic enabled: %d\n"
+		"hsic_opened: %d\n"
+		"hsic_suspend: %d\n"
+		"in_busy_hsic_read_on_device: %d\n"
+		"in_busy_hsic_write: %d\n"
+		"count_hsic_pool: %d\n"
+		"count_hsic_write_pool: %d\n"
+		"diag_hsic_pool: %x\n"
+		"diag_hsic_write_pool: %x\n"
+		"write_len_mdm: %d\n"
+		"num_hsic_buf_tbl_entries: %d\n"
+		"usb_mdm_connected: %d\n"
+		"diag_read_mdm_work: %d\n"
+		"diag_read_hsic_work: %d\n"
+		"diag_disconnect_work: %d\n"
+		"diag_usb_read_complete_work: %d\n",
+		driver->hsic_ch,
+		driver->hsic_inited,
+		driver->hsic_device_enabled,
+		driver->hsic_device_opened,
+		driver->hsic_suspend,
+		driver->in_busy_hsic_read_on_device,
+		driver->in_busy_hsic_write,
+		driver->count_hsic_pool,
+		driver->count_hsic_write_pool,
+		(unsigned int)driver->diag_hsic_pool,
+		(unsigned int)driver->diag_hsic_write_pool,
+		driver->write_len_mdm,
+		driver->num_hsic_buf_tbl_entries,
+		driver->usb_mdm_connected,
+		work_pending(&(driver->diag_read_mdm_work)),
+		work_pending(&(driver->diag_read_hsic_work)),
+		work_pending(&(driver->diag_disconnect_work)),
+		work_pending(&(driver->diag_usb_read_complete_work)));
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+const struct file_operations diag_dbgfs_hsic_ops = {
+	.read = diag_dbgfs_read_hsic,
+};
+#endif
+
+const struct file_operations diag_dbgfs_status_ops = {
+	.read = diag_dbgfs_read_status,
+};
+
+const struct file_operations diag_dbgfs_table_ops = {
+	.read = diag_dbgfs_read_table,
+};
+
+const struct file_operations diag_dbgfs_workpending_ops = {
+	.read = diag_dbgfs_read_workpending,
+};
+
+void diag_debugfs_init(void)
+{
+	diag_dbgfs_dent = debugfs_create_dir("diag", 0);
+	if (IS_ERR(diag_dbgfs_dent))
+		return;
+
+	debugfs_create_file("status", 0444, diag_dbgfs_dent, 0,
+		&diag_dbgfs_status_ops);
+
+	debugfs_create_file("table", 0444, diag_dbgfs_dent, 0,
+		&diag_dbgfs_table_ops);
+
+	debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
+		&diag_dbgfs_workpending_ops);
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+	debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
+		&diag_dbgfs_hsic_ops);
+#endif
+
+	diag_dbgfs_table_index = 0;
+}
+
+void diag_debugfs_cleanup(void)
+{
+	if (diag_dbgfs_dent) {
+		debugfs_remove_recursive(diag_dbgfs_dent);
+		diag_dbgfs_dent = NULL;
+	}
+}
+#else
+void diag_debugfs_init(void) { }
+void diag_debugfs_cleanup(void) { }
+#endif
diff --git a/drivers/char/diag/diag_debugfs.h b/drivers/char/diag/diag_debugfs.h
new file mode 100644
index 0000000..4bc8b0f
--- /dev/null
+++ b/drivers/char/diag/diag_debugfs.h
@@ -0,0 +1,19 @@
+/* Copyright (c)2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAG_DEBUGFS_H
+#define DIAG_DEBUGFS_H
+
+void diag_debugfs_init(void);
+void diag_debugfs_cleanup(void);
+
+#endif
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
new file mode 100644
index 0000000..5316548
--- /dev/null
+++ b/drivers/char/diag/diag_masks.c
@@ -0,0 +1,790 @@
+/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/diagchar.h>
+#include <linux/kmemleak.h>
+#include <linux/workqueue.h>
+#include "diagchar.h"
+#include "diagfwd_cntl.h"
+#include "diag_masks.h"
+
+int diag_event_config;
+int diag_event_num_bytes;
+
+#define ALL_EQUIP_ID		100
+#define ALL_SSID		-1
+#define MAX_SSID_PER_RANGE	100
+
+struct mask_info {
+	int equip_id;
+	int num_items;
+	int index;
+};
+
+#define CREATE_MSG_MASK_TBL_ROW(XX)					\
+do {									\
+	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX;			\
+	msg_mask_tbl_ptr += 4;						\
+	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
+	msg_mask_tbl_ptr += 4;						\
+	/* mimic the last entry as actual_last while creation */	\
+	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
+	msg_mask_tbl_ptr += 4;						\
+	/* increment by MAX_SSID_PER_RANGE cells */			\
+	msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int);		\
+} while (0)
+
+#define WAIT_FOR_SMD(num_delays, delay_time)		\
+do {							\
+	int count;					\
+	for (count = 0; count < (num_delays); count++)	\
+		udelay((delay_time));			\
+} while (0)
+
+static void diag_print_mask_table(void)
+{
+/* Enable this to print mask table when updated */
+#ifdef MASK_DEBUG
+	int first, last, actual_last;
+	uint8_t *ptr = driver->msg_masks;
+	int i = 0;
+	pr_info("diag: F3 message mask table\n");
+	while (*(uint32_t *)(ptr + 4)) {
+		first = *(uint32_t *)ptr;
+		ptr += 4;
+		last = *(uint32_t *)ptr;
+		ptr += 4;
+		actual_last = *(uint32_t *)ptr;
+		ptr += 4;
+		pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
+		for (i = 0 ; i <= actual_last - first ; i++)
+			pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
+		ptr += MAX_SSID_PER_RANGE*4;
+	}
+#endif
+}
+
+void diag_create_msg_mask_table(void)
+{
+	uint8_t *msg_mask_tbl_ptr = driver->msg_masks;
+
+	CREATE_MSG_MASK_TBL_ROW(0);
+	CREATE_MSG_MASK_TBL_ROW(1);
+	CREATE_MSG_MASK_TBL_ROW(2);
+	CREATE_MSG_MASK_TBL_ROW(3);
+	CREATE_MSG_MASK_TBL_ROW(4);
+	CREATE_MSG_MASK_TBL_ROW(5);
+	CREATE_MSG_MASK_TBL_ROW(6);
+	CREATE_MSG_MASK_TBL_ROW(7);
+	CREATE_MSG_MASK_TBL_ROW(8);
+	CREATE_MSG_MASK_TBL_ROW(9);
+	CREATE_MSG_MASK_TBL_ROW(10);
+	CREATE_MSG_MASK_TBL_ROW(11);
+	CREATE_MSG_MASK_TBL_ROW(12);
+	CREATE_MSG_MASK_TBL_ROW(13);
+	CREATE_MSG_MASK_TBL_ROW(14);
+	CREATE_MSG_MASK_TBL_ROW(15);
+	CREATE_MSG_MASK_TBL_ROW(16);
+	CREATE_MSG_MASK_TBL_ROW(17);
+	CREATE_MSG_MASK_TBL_ROW(18);
+	CREATE_MSG_MASK_TBL_ROW(19);
+	CREATE_MSG_MASK_TBL_ROW(20);
+	CREATE_MSG_MASK_TBL_ROW(21);
+	CREATE_MSG_MASK_TBL_ROW(22);
+	CREATE_MSG_MASK_TBL_ROW(23);
+}
+
+static void diag_set_msg_mask(int rt_mask)
+{
+	int first_ssid, last_ssid, i;
+	uint8_t *parse_ptr, *ptr = driver->msg_masks;
+
+	mutex_lock(&driver->diagchar_mutex);
+	while (*(uint32_t *)(ptr + 4)) {
+		first_ssid = *(uint32_t *)ptr;
+		ptr += 8; /* increment by 8 to skip 'last' */
+		last_ssid = *(uint32_t *)ptr;
+		ptr += 4;
+		parse_ptr = ptr;
+		pr_debug("diag: updating range %d %d\n", first_ssid, last_ssid);
+		for (i = 0; i < last_ssid - first_ssid + 1; i++) {
+			*(int *)parse_ptr = rt_mask;
+			parse_ptr += 4;
+		}
+		ptr += MAX_SSID_PER_RANGE * 4;
+	}
+	mutex_unlock(&driver->diagchar_mutex);
+}
+
+static void diag_update_msg_mask(int start, int end , uint8_t *buf)
+{
+	int found = 0, first, last, actual_last;
+	uint8_t *actual_last_ptr;
+	uint8_t *ptr = driver->msg_masks;
+	uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
+	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
+
+	mutex_lock(&driver->diagchar_mutex);
+
+	/* First SSID can be zero : So check that last is non-zero */
+	while (*(uint32_t *)(ptr + 4)) {
+		first = *(uint32_t *)ptr;
+		ptr += 4;
+		last = *(uint32_t *)ptr;
+		ptr += 4;
+		actual_last = *(uint32_t *)ptr;
+		actual_last_ptr = ptr;
+		ptr += 4;
+		if (start >= first && start <= actual_last) {
+			ptr += (start - first)*4;
+			if (end > actual_last) {
+				pr_info("diag: ssid range mismatch\n");
+				actual_last = end;
+				*(uint32_t *)(actual_last_ptr) = end;
+			}
+			if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+					  (((end - start)+1)*4))) {
+				pr_debug("diag: update ssid start %d, end %d\n",
+								 start, end);
+				memcpy(ptr, buf , ((end - start)+1)*4);
+			} else
+				pr_alert("diag: Not enough space MSG_MASK\n");
+			found = 1;
+			break;
+		} else {
+			ptr += MAX_SSID_PER_RANGE*4;
+		}
+	}
+	/* Entry was not found - add new table */
+	if (!found) {
+		if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+				  8 + ((end - start) + 1)*4)) {
+			memcpy(ptr, &(start) , 4);
+			ptr += 4;
+			memcpy(ptr, &(end), 4);
+			ptr += 4;
+			memcpy(ptr, &(end), 4); /* create actual_last entry */
+			ptr += 4;
+			pr_debug("diag: adding NEW ssid start %d, end %d\n",
+								 start, end);
+			memcpy(ptr, buf , ((end - start) + 1)*4);
+		} else
+			pr_alert("diag: Not enough buffer space for MSG_MASK\n");
+	}
+	mutex_unlock(&driver->diagchar_mutex);
+	diag_print_mask_table();
+}
+
+void diag_toggle_event_mask(int toggle)
+{
+	uint8_t *ptr = driver->event_masks;
+
+	mutex_lock(&driver->diagchar_mutex);
+	if (toggle)
+		memset(ptr, 0xFF, EVENT_MASK_SIZE);
+	else
+		memset(ptr, 0, EVENT_MASK_SIZE);
+	mutex_unlock(&driver->diagchar_mutex);
+}
+
+
+static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
+{
+	uint8_t *ptr = driver->event_masks;
+	uint8_t *temp = buf + 2;
+
+	mutex_lock(&driver->diagchar_mutex);
+	if (!toggle)
+		memset(ptr, 0 , EVENT_MASK_SIZE);
+	else
+		if (CHK_OVERFLOW(ptr, ptr,
+				 ptr+EVENT_MASK_SIZE, num_bytes))
+			memcpy(ptr, temp , num_bytes);
+		else
+			printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
+	mutex_unlock(&driver->diagchar_mutex);
+}
+
+static void diag_disable_log_mask(void)
+{
+	int i = 0;
+	struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
+
+	pr_debug("diag: disable log masks\n");
+	mutex_lock(&driver->diagchar_mutex);
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
+		if (!(parse_ptr->equip_id)) /* Reached a null entry */
+			break;
+		memset(driver->log_masks + parse_ptr->index, 0,
+			    (parse_ptr->num_items + 7)/8);
+		parse_ptr++;
+	}
+	mutex_unlock(&driver->diagchar_mutex);
+}
+
+int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+{
+	int i = 0, flag = 0, num_items, offset;
+	unsigned char *ptr_data;
+	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+
+	pr_debug("diag: received equip id = %d\n", equip_id);
+	/* Check if this is valid equipment ID */
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
+			offset = ptr->index;
+			num_items = ptr->num_items;
+			flag = 1;
+			break;
+		}
+		ptr++;
+	}
+	if (!flag)
+		return -EPERM;
+	ptr_data = driver->log_masks + offset;
+	memcpy(buf, ptr_data, (num_items+7)/8);
+	return 0;
+}
+
+static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
+{
+	uint8_t *temp = buf;
+	int i = 0;
+	unsigned char *ptr_data;
+	int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+
+	pr_debug("diag: received equip id = %d\n", equip_id);
+	mutex_lock(&driver->diagchar_mutex);
+	/* Check if we already know index of this equipment ID */
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
+			offset = ptr->index;
+			break;
+		}
+		if ((ptr->equip_id == 0) && (ptr->index == 0)) {
+			/* Reached a null entry */
+			ptr->equip_id = equip_id;
+			ptr->num_items = num_items;
+			ptr->index = driver->log_masks_length;
+			offset = driver->log_masks_length;
+			driver->log_masks_length += ((num_items+7)/8);
+			break;
+		}
+		ptr++;
+	}
+	ptr_data = driver->log_masks + offset;
+	if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
+					 + LOG_MASK_SIZE, (num_items+7)/8))
+		memcpy(ptr_data, temp , (num_items+7)/8);
+	else
+		pr_err("diag: Not enough buffer space for LOG_MASK\n");
+	mutex_unlock(&driver->diagchar_mutex);
+}
+
+void diag_modem_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->ch_cntl, ALL_SSID,
+					   ALL_SSID, MODEM_PROC);
+	diag_send_log_mask_update(driver->ch_cntl, ALL_EQUIP_ID);
+	diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
+}
+
+void diag_lpass_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
+						   ALL_SSID, LPASS_PROC);
+	diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
+	diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
+}
+
+void diag_wcnss_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->ch_wcnss_cntl, ALL_SSID,
+						   ALL_SSID, WCNSS_PROC);
+	diag_send_log_mask_update(driver->ch_wcnss_cntl, ALL_EQUIP_ID);
+	diag_send_event_mask_update(driver->ch_wcnss_cntl,
+						 diag_event_num_bytes);
+}
+
+void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
+{
+	void *buf = driver->buf_log_mask_update;
+	int header_size = sizeof(struct diag_ctrl_log_mask);
+	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
+	int i, size, wr_size = -ENOMEM, retry_count = 0;
+
+	mutex_lock(&driver->diag_cntl_mutex);
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		size = (ptr->num_items+7)/8;
+		/* reached null entry */
+		if ((ptr->equip_id == 0) && (ptr->index == 0))
+			break;
+		driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+		driver->log_mask->num_items = ptr->num_items;
+		driver->log_mask->data_len  = 11 + size;
+		driver->log_mask->stream_id = 1; /* 2, if dual stream */
+		driver->log_mask->status = 3; /* status for valid mask */
+		driver->log_mask->equip_id = ptr->equip_id;
+		driver->log_mask->log_mask_size = size;
+		/* send only desired update, NOT ALL */
+		if (equip_id == ALL_EQUIP_ID || equip_id ==
+					 driver->log_mask->equip_id) {
+			memcpy(buf, driver->log_mask, header_size);
+			memcpy(buf+header_size, driver->log_masks+ptr->index,
+									 size);
+			if (ch) {
+				while (retry_count < 3) {
+					wr_size = smd_write(ch, buf,
+							 header_size + size);
+					if (wr_size == -ENOMEM) {
+						retry_count++;
+						WAIT_FOR_SMD(5, 2000);
+					} else
+						break;
+				}
+				if (wr_size != header_size + size)
+					pr_err("diag: log mask update failed %d, tried %d",
+						wr_size, header_size + size);
+				else
+					pr_debug("diag: updated log equip ID %d,len %d\n",
+					driver->log_mask->equip_id,
+					driver->log_mask->log_mask_size);
+			} else
+				pr_err("diag: ch not valid for log update\n");
+		}
+		ptr++;
+	}
+	mutex_unlock(&driver->diag_cntl_mutex);
+}
+
+void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
+{
+	void *buf = driver->buf_event_mask_update;
+	int header_size = sizeof(struct diag_ctrl_event_mask);
+	int wr_size = -ENOMEM, retry_count = 0;
+
+	mutex_lock(&driver->diag_cntl_mutex);
+	if (num_bytes == 0) {
+		pr_debug("diag: event mask not set yet, so no update\n");
+		mutex_unlock(&driver->diag_cntl_mutex);
+		return;
+	}
+	/* send event mask update */
+	driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
+	driver->event_mask->data_len = 7 + num_bytes;
+	driver->event_mask->stream_id = 1; /* 2, if dual stream */
+	driver->event_mask->status = 3; /* status for valid mask */
+	driver->event_mask->event_config = diag_event_config; /* event config */
+	driver->event_mask->event_mask_size = num_bytes;
+	memcpy(buf, driver->event_mask, header_size);
+	memcpy(buf+header_size, driver->event_masks, num_bytes);
+	if (ch) {
+		while (retry_count < 3) {
+			wr_size = smd_write(ch, buf, header_size + num_bytes);
+			if (wr_size == -ENOMEM) {
+				retry_count++;
+				WAIT_FOR_SMD(5, 2000);
+			} else
+				break;
+		}
+		if (wr_size != header_size + num_bytes)
+			pr_err("diag: error writing event mask %d, tried %d\n",
+					 wr_size, header_size + num_bytes);
+	} else
+		pr_err("diag: ch not valid for event update\n");
+	mutex_unlock(&driver->diag_cntl_mutex);
+}
+
+void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
+						int updated_ssid_last, int proc)
+{
+	void *buf = driver->buf_msg_mask_update;
+	int first, last, actual_last, size = -ENOMEM, retry_count = 0;
+	int header_size = sizeof(struct diag_ctrl_msg_mask);
+	uint8_t *ptr = driver->msg_masks;
+
+	mutex_lock(&driver->diag_cntl_mutex);
+	while (*(uint32_t *)(ptr + 4)) {
+		first = *(uint32_t *)ptr;
+		ptr += 4;
+		last = *(uint32_t *)ptr;
+		ptr += 4;
+		actual_last = *(uint32_t *)ptr;
+		ptr += 4;
+		if ((updated_ssid_first >= first && updated_ssid_last <=
+			 actual_last) || (updated_ssid_first == ALL_SSID)) {
+			/* send f3 mask update */
+			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+			driver->msg_mask->msg_mask_size = actual_last -
+								 first + 1;
+			driver->msg_mask->data_len = 11 +
+					 4 * (driver->msg_mask->msg_mask_size);
+			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+			driver->msg_mask->status = 3; /* status valid mask */
+			driver->msg_mask->msg_mode = 0; /* Legcay mode */
+			driver->msg_mask->ssid_first = first;
+			driver->msg_mask->ssid_last = actual_last;
+			memcpy(buf, driver->msg_mask, header_size);
+			memcpy(buf+header_size, ptr,
+				 4 * (driver->msg_mask->msg_mask_size));
+			if (ch) {
+				while (retry_count < 3) {
+					size = smd_write(ch, buf, header_size +
+					 4*(driver->msg_mask->msg_mask_size));
+					if (size == -ENOMEM) {
+						retry_count++;
+						WAIT_FOR_SMD(5, 2000);
+					} else
+						break;
+				}
+				if (size != header_size +
+					 4*(driver->msg_mask->msg_mask_size))
+					pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
+						proc, size, (header_size +
+					4*(driver->msg_mask->msg_mask_size)));
+				else
+					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+						first, actual_last, proc);
+			} else
+				pr_err("diag: proc %d, ch invalid msg mask update\n",
+					proc);
+		}
+		ptr += MAX_SSID_PER_RANGE*4;
+	}
+	mutex_unlock(&driver->diag_cntl_mutex);
+}
+
+int diag_process_apps_masks(unsigned char *buf, int len)
+{
+	int packet_type = 1;
+	int i;
+	int ssid_first, ssid_last, ssid_range;
+	int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
+	uint8_t *rt_mask_ptr;
+	int equip_id, num_items;
+#if defined(CONFIG_DIAG_OVER_USB)
+	int payload_length;
+#endif
+
+	/* Set log masks */
+	if (*buf == 0x73 && *(int *)(buf+4) == 3) {
+		buf += 8;
+		/* Read Equip ID and pass as first param below*/
+		diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
+		diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x73;
+			*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
+			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
+			payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+			for (i = 0; i < payload_length; i++)
+				*(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
+			if (driver->ch_cntl)
+				diag_send_log_mask_update(driver->ch_cntl,
+				*(int *)buf);
+			if (driver->chlpass_cntl)
+				diag_send_log_mask_update(driver->chlpass_cntl,
+				*(int *)buf);
+			if (driver->ch_wcnss_cntl)
+				diag_send_log_mask_update(driver->ch_wcnss_cntl,
+				*(int *)buf);
+			encode_rsp_and_send(12 + payload_length - 1);
+			return 0;
+		}
+#endif
+	} /* Get log masks */
+	else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (!(driver->ch) && chk_apps_only()) {
+			equip_id = *(int *)(buf + 8);
+			num_items = *(int *)(buf + 12);
+			driver->apps_rsp_buf[0] = 0x73;
+			driver->apps_rsp_buf[1] = 0x0;
+			driver->apps_rsp_buf[2] = 0x0;
+			driver->apps_rsp_buf[3] = 0x0;
+			*(int *)(driver->apps_rsp_buf + 4) = 0x4;
+			if (!chk_equip_id_and_mask(equip_id,
+				driver->apps_rsp_buf+20))
+				*(int *)(driver->apps_rsp_buf + 8) = 0x0;
+			else
+				*(int *)(driver->apps_rsp_buf + 8) = 0x1;
+			*(int *)(driver->apps_rsp_buf + 12) = equip_id;
+			*(int *)(driver->apps_rsp_buf + 16) = num_items;
+			encode_rsp_and_send(20+(num_items+7)/8-1);
+			return 0;
+		}
+#endif
+	} /* Disable log masks */
+	else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
+		/* Disable mask for each log code */
+		diag_disable_log_mask();
+		diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x73;
+			driver->apps_rsp_buf[1] = 0x0;
+			driver->apps_rsp_buf[2] = 0x0;
+			driver->apps_rsp_buf[3] = 0x0;
+			*(int *)(driver->apps_rsp_buf + 4) = 0x0;
+			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
+			if (driver->ch_cntl)
+				diag_send_log_mask_update(driver->ch_cntl,
+				ALL_EQUIP_ID);
+			if (driver->chlpass_cntl)
+				diag_send_log_mask_update(driver->chlpass_cntl,
+				ALL_EQUIP_ID);
+			if (driver->ch_wcnss_cntl)
+				diag_send_log_mask_update(driver->ch_wcnss_cntl,
+				ALL_EQUIP_ID);
+			encode_rsp_and_send(11);
+			return 0;
+		}
+#endif
+	} /* Get runtime message mask  */
+	else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
+		ssid_first = *(uint16_t *)(buf + 2);
+		ssid_last = *(uint16_t *)(buf + 4);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (!(driver->ch) && chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x7d;
+			driver->apps_rsp_buf[1] = 0x3;
+			*(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
+			*(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
+			driver->apps_rsp_buf[6] = 0x1; /* Success Status */
+			driver->apps_rsp_buf[7] = 0x0;
+			rt_mask_ptr = driver->msg_masks;
+			while (*(uint32_t *)(rt_mask_ptr + 4)) {
+				rt_first_ssid = *(uint32_t *)rt_mask_ptr;
+				rt_mask_ptr += 8; /* +8 to skip 'last' */
+				rt_last_ssid = *(uint32_t *)rt_mask_ptr;
+				rt_mask_ptr += 4;
+				if (ssid_first == rt_first_ssid && ssid_last ==
+					rt_last_ssid) {
+					rt_mask_size = 4 * (rt_last_ssid -
+						rt_first_ssid + 1);
+					memcpy(driver->apps_rsp_buf+8,
+						rt_mask_ptr, rt_mask_size);
+					encode_rsp_and_send(8+rt_mask_size-1);
+					return 0;
+				}
+				rt_mask_ptr += MAX_SSID_PER_RANGE*4;
+			}
+		}
+#endif
+	} /* Set runtime message mask  */
+	else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
+		ssid_first = *(uint16_t *)(buf + 2);
+		ssid_last = *(uint16_t *)(buf + 4);
+		ssid_range = 4 * (ssid_last - ssid_first + 1);
+		pr_debug("diag: received mask update for ssid_first = %d, ssid_last = %d",
+			ssid_first, ssid_last);
+		diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
+		diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			for (i = 0; i < 8 + ssid_range; i++)
+				*(driver->apps_rsp_buf + i) = *(buf+i);
+			*(driver->apps_rsp_buf + 6) = 0x1;
+			if (driver->ch_cntl)
+				diag_send_msg_mask_update(driver->ch_cntl,
+				ssid_first, ssid_last, MODEM_PROC);
+			if (driver->chlpass_cntl)
+				diag_send_msg_mask_update(driver->chlpass_cntl,
+				ssid_first, ssid_last, LPASS_PROC);
+			if (driver->ch_wcnss_cntl)
+				diag_send_msg_mask_update(driver->ch_wcnss_cntl,
+				ssid_first, ssid_last, WCNSS_PROC);
+			encode_rsp_and_send(8 + ssid_range - 1);
+			return 0;
+		}
+#endif
+	} /* Set ALL runtime message mask  */
+	else if ((*buf == 0x7d) && (*(buf+1) == 0x5)) {
+		rt_mask = *(int *)(buf + 4);
+		diag_set_msg_mask(rt_mask);
+		diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x7d; /* cmd_code */
+			driver->apps_rsp_buf[1] = 0x5; /* set subcommand */
+			driver->apps_rsp_buf[2] = 1; /* success */
+			driver->apps_rsp_buf[3] = 0; /* rsvd */
+			*(int *)(driver->apps_rsp_buf + 4) = rt_mask;
+			/* send msg mask update to peripheral */
+			if (driver->ch_cntl)
+				diag_send_msg_mask_update(driver->ch_cntl,
+				ALL_SSID, ALL_SSID, MODEM_PROC);
+			if (driver->chlpass_cntl)
+				diag_send_msg_mask_update(driver->chlpass_cntl,
+				ALL_SSID, ALL_SSID, LPASS_PROC);
+			if (driver->ch_wcnss_cntl)
+				diag_send_msg_mask_update(driver->ch_wcnss_cntl,
+				ALL_SSID, ALL_SSID, WCNSS_PROC);
+			encode_rsp_and_send(7);
+			return 0;
+		}
+#endif
+	} else if (*buf == 0x82) {	/* event mask change */
+		buf += 4;
+		diag_event_num_bytes =  (*(uint16_t *)buf)/8+1;
+		diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+		diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x82;
+			driver->apps_rsp_buf[1] = 0x0;
+			*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
+			*(uint16_t *)(driver->apps_rsp_buf + 4) =
+				EVENT_LAST_ID + 1;
+			memcpy(driver->apps_rsp_buf+6, driver->event_masks,
+				EVENT_LAST_ID/8+1);
+			if (driver->ch_cntl)
+				diag_send_event_mask_update(driver->ch_cntl,
+				diag_event_num_bytes);
+			if (driver->chlpass_cntl)
+				diag_send_event_mask_update(
+				driver->chlpass_cntl,
+				diag_event_num_bytes);
+			if (driver->ch_wcnss_cntl)
+				diag_send_event_mask_update(
+				driver->ch_wcnss_cntl, diag_event_num_bytes);
+			encode_rsp_and_send(6 + EVENT_LAST_ID/8);
+			return 0;
+		}
+#endif
+	} else if (*buf == 0x60) {
+		diag_event_config = *(buf+1);
+		diag_toggle_event_mask(*(buf+1));
+		diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x60;
+			driver->apps_rsp_buf[1] = 0x0;
+			driver->apps_rsp_buf[2] = 0x0;
+			if (driver->ch_cntl)
+				diag_send_event_mask_update(driver->ch_cntl,
+				diag_event_num_bytes);
+			if (driver->chlpass_cntl)
+				diag_send_event_mask_update(
+				driver->chlpass_cntl,
+				diag_event_num_bytes);
+			if (driver->ch_wcnss_cntl)
+				diag_send_event_mask_update(
+				driver->ch_wcnss_cntl, diag_event_num_bytes);
+			encode_rsp_and_send(2);
+			return 0;
+		}
+#endif
+	}
+
+	return  packet_type;
+}
+
+void diag_masks_init(void)
+{
+	if (driver->event_mask == NULL) {
+		driver->event_mask = kzalloc(sizeof(
+			struct diag_ctrl_event_mask), GFP_KERNEL);
+		if (driver->event_mask == NULL)
+			goto err;
+		kmemleak_not_leak(driver->event_mask);
+	}
+	if (driver->msg_mask == NULL) {
+		driver->msg_mask = kzalloc(sizeof(
+			struct diag_ctrl_msg_mask), GFP_KERNEL);
+		if (driver->msg_mask == NULL)
+			goto err;
+		kmemleak_not_leak(driver->msg_mask);
+	}
+	if (driver->log_mask == NULL) {
+		driver->log_mask = kzalloc(sizeof(
+			struct diag_ctrl_log_mask), GFP_KERNEL);
+		if (driver->log_mask == NULL)
+			goto err;
+		kmemleak_not_leak(driver->log_mask);
+	}
+
+	if (driver->buf_msg_mask_update == NULL) {
+		driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
+								 GFP_KERNEL);
+		if (driver->buf_msg_mask_update == NULL)
+			goto err;
+		kmemleak_not_leak(driver->buf_msg_mask_update);
+	}
+	if (driver->buf_log_mask_update == NULL) {
+		driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
+								 GFP_KERNEL);
+		if (driver->buf_log_mask_update == NULL)
+			goto err;
+		kmemleak_not_leak(driver->buf_log_mask_update);
+	}
+	if (driver->buf_event_mask_update == NULL) {
+		driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
+								 GFP_KERNEL);
+		if (driver->buf_event_mask_update == NULL)
+			goto err;
+		kmemleak_not_leak(driver->buf_event_mask_update);
+	}
+	if (driver->msg_masks == NULL) {
+		driver->msg_masks = kzalloc(MSG_MASK_SIZE, GFP_KERNEL);
+		if (driver->msg_masks == NULL)
+			goto err;
+		kmemleak_not_leak(driver->msg_masks);
+	}
+	diag_create_msg_mask_table();
+	diag_event_num_bytes = 0;
+	if (driver->log_masks == NULL) {
+		driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL);
+		if (driver->log_masks == NULL)
+			goto err;
+		kmemleak_not_leak(driver->log_masks);
+	}
+	driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+	if (driver->event_masks == NULL) {
+		driver->event_masks = kzalloc(EVENT_MASK_SIZE, GFP_KERNEL);
+		if (driver->event_masks == NULL)
+			goto err;
+		kmemleak_not_leak(driver->event_masks);
+	}
+#ifdef CONFIG_DIAG_OVER_USB
+	INIT_WORK(&(driver->diag_modem_mask_update_work),
+						 diag_modem_mask_update_fn);
+	INIT_WORK(&(driver->diag_lpass_mask_update_work),
+						 diag_lpass_mask_update_fn);
+	INIT_WORK(&(driver->diag_wcnss_mask_update_work),
+						 diag_wcnss_mask_update_fn);
+#endif
+	return;
+err:
+	pr_err("diag: Could not initialize diag mask buffers");
+	kfree(driver->event_mask);
+	kfree(driver->log_mask);
+	kfree(driver->msg_mask);
+	kfree(driver->msg_masks);
+	kfree(driver->log_masks);
+	kfree(driver->event_masks);
+}
+
+void diag_masks_exit(void)
+{
+	kfree(driver->event_mask);
+	kfree(driver->log_mask);
+	kfree(driver->msg_mask);
+	kfree(driver->msg_masks);
+	kfree(driver->log_masks);
+	kfree(driver->event_masks);
+}
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
new file mode 100644
index 0000000..bcf5bc2
--- /dev/null
+++ b/drivers/char/diag/diag_masks.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAG_MASKS_H
+#define DIAG_MASKS_H
+
+#include "diagfwd.h"
+
+int chk_equip_id_and_mask(int equip_id, uint8_t *buf);
+void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
+void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
+					 int ssid_last, int proc);
+void diag_send_log_mask_update(smd_channel_t *, int);
+int diag_process_apps_masks(unsigned char *buf, int len);
+void diag_masks_init(void);
+void diag_masks_exit(void);
+extern int diag_event_num_bytes;
+#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 814fe64..5c6cdc6 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -37,6 +37,8 @@
 #include "diagfwd_smux.h"
 #endif
 #include <linux/timer.h>
+#include "diag_debugfs.h"
+#include "diag_masks.h"
 
 MODULE_DESCRIPTION("Diag Char Driver");
 MODULE_LICENSE("GPL v2");
@@ -1420,6 +1422,7 @@
 		INIT_WORK(&(driver->diag_clean_wcnss_reg_work),
 						 diag_clean_wcnss_reg_fn);
 		diag_debugfs_init();
+		diag_masks_init();
 		diagfwd_init();
 		diagfwd_cntl_init();
 		driver->dci_state = diag_dci_init();
@@ -1457,6 +1460,7 @@
 	diagchar_cleanup();
 	diagfwd_exit();
 	diagfwd_cntl_exit();
+	diag_masks_exit();
 	diag_sdio_fn(EXIT);
 	diag_bridge_fn(EXIT);
 	return -1;
@@ -1470,6 +1474,7 @@
 	diagmem_exit(driver, POOL_TYPE_ALL);
 	diagfwd_exit();
 	diagfwd_cntl_exit();
+	diag_masks_exit();
 	diag_sdio_fn(EXIT);
 	diag_bridge_fn(EXIT);
 	diag_debugfs_cleanup();
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 737edbf..a537bb3 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -39,63 +39,38 @@
 #include "diagfwd_sdio.h"
 #endif
 #include "diag_dci.h"
+#include "diag_masks.h"
 
 #define MODE_CMD		41
 #define RESET_ID		2
-#define ALL_EQUIP_ID		100
-#define ALL_SSID		-1
-#define MAX_SSID_PER_RANGE	100
 
 int diag_debug_buf_idx;
 unsigned char diag_debug_buf[1024];
 static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
 struct diag_master_table entry;
 smd_channel_t *ch_temp = NULL, *chlpass_temp = NULL, *ch_wcnss_temp = NULL;
-int diag_event_num_bytes;
-int diag_event_config;
 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
-struct mask_info {
-	int equip_id;
-	int num_items;
-	int index;
-};
 
-#define CREATE_MSG_MASK_TBL_ROW(XX)					\
-do {									\
-	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX;			\
-	msg_mask_tbl_ptr += 4;						\
-	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
-	msg_mask_tbl_ptr += 4;						\
-	/* mimic the last entry as actual_last while creation */	\
-	*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST;		\
-	msg_mask_tbl_ptr += 4;						\
-	/* increment by MAX_SSID_PER_RANGE cells */			\
-	msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int);		\
-} while (0)
-
-#define ENCODE_RSP_AND_SEND(buf_length)				\
-do {									\
-	send.state = DIAG_STATE_START;					\
-	send.pkt = driver->apps_rsp_buf;				\
-	send.last = (void *)(driver->apps_rsp_buf + buf_length);	\
-	send.terminate = 1;						\
-	if (!driver->in_busy_1) {					\
-		enc.dest = driver->buf_in_1;				\
-		enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);\
-		diag_hdlc_encode(&send, &enc);				\
-		driver->write_ptr_1->buf = driver->buf_in_1;		\
-		driver->write_ptr_1->length = (int)(enc.dest - \
-						(void *)(driver->buf_in_1)); \
-		driver->in_busy_1 = 1;					\
-		diag_device_write(driver->buf_in_1, MODEM_DATA, \
-						 driver->write_ptr_1); \
-		memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);	\
-	}								\
-} while (0)
-
-#define CHK_OVERFLOW(bufStart, start, end, length) \
-((bufStart <= start) && (end - start >= length)) ? 1 : 0
+void encode_rsp_and_send(int buf_length)
+{
+	send.state = DIAG_STATE_START;
+	send.pkt = driver->apps_rsp_buf;
+	send.last = (void *)(driver->apps_rsp_buf + buf_length);
+	send.terminate = 1;
+	if (!driver->in_busy_1) {
+		enc.dest = driver->buf_in_1;
+		enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);
+		diag_hdlc_encode(&send, &enc);
+		driver->write_ptr_1->buf = driver->buf_in_1;
+		driver->write_ptr_1->length = (int)(enc.dest -
+						(void *)(driver->buf_in_1));
+		driver->in_busy_1 = 1;
+		diag_device_write(driver->buf_in_1, MODEM_DATA,
+					driver->write_ptr_1);
+		memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
+	}
+}
 
 /* Determine if this device uses a device tree */
 #ifdef CONFIG_OF
@@ -136,6 +111,7 @@
 		case MSM_CPU_8960AB:
 			return AO8960_TOOLS_ID;
 		case MSM_CPU_8064:
+		case MSM_CPU_8064AB:
 			return APQ8064_TOOLS_ID;
 		case MSM_CPU_8930:
 		case MSM_CPU_8930AA:
@@ -163,6 +139,7 @@
 	case MSM_CPU_8960:
 	case MSM_CPU_8960AB:
 	case MSM_CPU_8064:
+	case MSM_CPU_8064AB:
 	case MSM_CPU_8930:
 	case MSM_CPU_8930AA:
 	case MSM_CPU_8627:
@@ -185,7 +162,7 @@
 		return 1;
 	else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
 		cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
-		cpu_is_msm8960ab())
+		cpu_is_msm8960ab() || cpu_is_apq8064ab())
 		return 1;
 	else
 		return 0;
@@ -559,248 +536,6 @@
 	}
 }
 
-static void diag_print_mask_table(void)
-{
-/* Enable this to print mask table when updated */
-#ifdef MASK_DEBUG
-	int first, last, actual_last;
-	uint8_t *ptr = driver->msg_masks;
-	int i = 0;
-	pr_info("diag: F3 message mask table\n");
-	while (*(uint32_t *)(ptr + 4)) {
-		first = *(uint32_t *)ptr;
-		ptr += 4;
-		last = *(uint32_t *)ptr;
-		ptr += 4;
-		actual_last = *(uint32_t *)ptr;
-		ptr += 4;
-		pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
-		for (i = 0 ; i <= actual_last - first ; i++)
-			pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
-		ptr += MAX_SSID_PER_RANGE*4;
-	}
-#endif
-}
-
-void diag_create_msg_mask_table(void)
-{
-	uint8_t *msg_mask_tbl_ptr = driver->msg_masks;
-
-	CREATE_MSG_MASK_TBL_ROW(0);
-	CREATE_MSG_MASK_TBL_ROW(1);
-	CREATE_MSG_MASK_TBL_ROW(2);
-	CREATE_MSG_MASK_TBL_ROW(3);
-	CREATE_MSG_MASK_TBL_ROW(4);
-	CREATE_MSG_MASK_TBL_ROW(5);
-	CREATE_MSG_MASK_TBL_ROW(6);
-	CREATE_MSG_MASK_TBL_ROW(7);
-	CREATE_MSG_MASK_TBL_ROW(8);
-	CREATE_MSG_MASK_TBL_ROW(9);
-	CREATE_MSG_MASK_TBL_ROW(10);
-	CREATE_MSG_MASK_TBL_ROW(11);
-	CREATE_MSG_MASK_TBL_ROW(12);
-	CREATE_MSG_MASK_TBL_ROW(13);
-	CREATE_MSG_MASK_TBL_ROW(14);
-	CREATE_MSG_MASK_TBL_ROW(15);
-	CREATE_MSG_MASK_TBL_ROW(16);
-	CREATE_MSG_MASK_TBL_ROW(17);
-	CREATE_MSG_MASK_TBL_ROW(18);
-	CREATE_MSG_MASK_TBL_ROW(19);
-	CREATE_MSG_MASK_TBL_ROW(20);
-	CREATE_MSG_MASK_TBL_ROW(21);
-	CREATE_MSG_MASK_TBL_ROW(22);
-	CREATE_MSG_MASK_TBL_ROW(23);
-}
-
-static void diag_set_msg_mask(int rt_mask)
-{
-	int first_ssid, last_ssid, i;
-	uint8_t *parse_ptr, *ptr = driver->msg_masks;
-
-	mutex_lock(&driver->diagchar_mutex);
-	while (*(uint32_t *)(ptr + 4)) {
-		first_ssid = *(uint32_t *)ptr;
-		ptr += 8; /* increment by 8 to skip 'last' */
-		last_ssid = *(uint32_t *)ptr;
-		ptr += 4;
-		parse_ptr = ptr;
-		pr_debug("diag: updating range %d %d\n", first_ssid, last_ssid);
-		for (i = 0; i < last_ssid - first_ssid + 1; i++) {
-			*(int *)parse_ptr = rt_mask;
-			parse_ptr += 4;
-		}
-		ptr += MAX_SSID_PER_RANGE * 4;
-	}
-	mutex_unlock(&driver->diagchar_mutex);
-}
-
-static void diag_update_msg_mask(int start, int end , uint8_t *buf)
-{
-	int found = 0, first, last, actual_last;
-	uint8_t *actual_last_ptr;
-	uint8_t *ptr = driver->msg_masks;
-	uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
-	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
-
-	mutex_lock(&driver->diagchar_mutex);
-
-	/* First SSID can be zero : So check that last is non-zero */
-	while (*(uint32_t *)(ptr + 4)) {
-		first = *(uint32_t *)ptr;
-		ptr += 4;
-		last = *(uint32_t *)ptr;
-		ptr += 4;
-		actual_last = *(uint32_t *)ptr;
-		actual_last_ptr = ptr;
-		ptr += 4;
-		if (start >= first && start <= actual_last) {
-			ptr += (start - first)*4;
-			if (end > actual_last) {
-				pr_info("diag: ssid range mismatch\n");
-				actual_last = end;
-				*(uint32_t *)(actual_last_ptr) = end;
-			}
-			if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
-					  (((end - start)+1)*4))) {
-				pr_debug("diag: update ssid start %d, end %d\n",
-								 start, end);
-				memcpy(ptr, buf , ((end - start)+1)*4);
-			} else
-				pr_alert("diag: Not enough space MSG_MASK\n");
-			found = 1;
-			break;
-		} else {
-			ptr += MAX_SSID_PER_RANGE*4;
-		}
-	}
-	/* Entry was not found - add new table */
-	if (!found) {
-		if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
-				  8 + ((end - start) + 1)*4)) {
-			memcpy(ptr, &(start) , 4);
-			ptr += 4;
-			memcpy(ptr, &(end), 4);
-			ptr += 4;
-			memcpy(ptr, &(end), 4); /* create actual_last entry */
-			ptr += 4;
-			pr_debug("diag: adding NEW ssid start %d, end %d\n",
-								 start, end);
-			memcpy(ptr, buf , ((end - start) + 1)*4);
-		} else
-			pr_alert("diag: Not enough buffer space for MSG_MASK\n");
-	}
-	mutex_unlock(&driver->diagchar_mutex);
-	diag_print_mask_table();
-}
-
-void diag_toggle_event_mask(int toggle)
-{
-	uint8_t *ptr = driver->event_masks;
-
-	mutex_lock(&driver->diagchar_mutex);
-	if (toggle)
-		memset(ptr, 0xFF, EVENT_MASK_SIZE);
-	else
-		memset(ptr, 0, EVENT_MASK_SIZE);
-	mutex_unlock(&driver->diagchar_mutex);
-}
-
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
-{
-	uint8_t *ptr = driver->event_masks;
-	uint8_t *temp = buf + 2;
-
-	mutex_lock(&driver->diagchar_mutex);
-	if (!toggle)
-		memset(ptr, 0 , EVENT_MASK_SIZE);
-	else
-		if (CHK_OVERFLOW(ptr, ptr,
-				 ptr+EVENT_MASK_SIZE, num_bytes))
-			memcpy(ptr, temp , num_bytes);
-		else
-			printk(KERN_CRIT "Not enough buffer space "
-					 "for EVENT_MASK\n");
-	mutex_unlock(&driver->diagchar_mutex);
-}
-
-static void diag_disable_log_mask(void)
-{
-	int i = 0;
-	struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
-
-	pr_debug("diag: disable log masks\n");
-	mutex_lock(&driver->diagchar_mutex);
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
-		if (!(parse_ptr->equip_id)) /* Reached a null entry */
-			break;
-		memset(driver->log_masks + parse_ptr->index, 0,
-			    (parse_ptr->num_items + 7)/8);
-		parse_ptr++;
-	}
-	mutex_unlock(&driver->diagchar_mutex);
-}
-
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
-{
-	int i = 0, flag = 0, num_items, offset;
-	unsigned char *ptr_data;
-	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
-
-	pr_debug("diag: received equip id = %d\n", equip_id);
-	/* Check if this is valid equipment ID */
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
-			offset = ptr->index;
-			num_items = ptr->num_items;
-			flag = 1;
-			break;
-		}
-		ptr++;
-	}
-	if (!flag)
-		return -EPERM;
-	ptr_data = driver->log_masks + offset;
-	memcpy(buf, ptr_data, (num_items+7)/8);
-	return 0;
-}
-
-static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
-{
-	uint8_t *temp = buf;
-	int i = 0;
-	unsigned char *ptr_data;
-	int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
-	struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
-
-	pr_debug("diag: received equip id = %d\n", equip_id);
-	mutex_lock(&driver->diagchar_mutex);
-	/* Check if we already know index of this equipment ID */
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
-			offset = ptr->index;
-			break;
-		}
-		if ((ptr->equip_id == 0) && (ptr->index == 0)) {
-			/* Reached a null entry */
-			ptr->equip_id = equip_id;
-			ptr->num_items = num_items;
-			ptr->index = driver->log_masks_length;
-			offset = driver->log_masks_length;
-			driver->log_masks_length += ((num_items+7)/8);
-			break;
-		}
-		ptr++;
-	}
-	ptr_data = driver->log_masks + offset;
-	if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
-					 + LOG_MASK_SIZE, (num_items+7)/8))
-		memcpy(ptr_data, temp , (num_items+7)/8);
-	else
-		pr_err("diag: Not enough buffer space for LOG_MASK\n");
-	mutex_unlock(&driver->diagchar_mutex);
-}
-
 static void diag_update_pkt_buffer(unsigned char *buf)
 {
 	unsigned char *ptr = driver->pkt_buf;
@@ -869,415 +604,21 @@
 	}
 }
 
-void diag_modem_mask_update_fn(struct work_struct *work)
-{
-	diag_send_msg_mask_update(driver->ch_cntl, ALL_SSID,
-					   ALL_SSID, MODEM_PROC);
-	diag_send_log_mask_update(driver->ch_cntl, ALL_EQUIP_ID);
-	diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
-}
-
-void diag_lpass_mask_update_fn(struct work_struct *work)
-{
-	diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
-						   ALL_SSID, LPASS_PROC);
-	diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
-	diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
-}
-
-void diag_wcnss_mask_update_fn(struct work_struct *work)
-{
-	diag_send_msg_mask_update(driver->ch_wcnss_cntl, ALL_SSID,
-						   ALL_SSID, WCNSS_PROC);
-	diag_send_log_mask_update(driver->ch_wcnss_cntl, ALL_EQUIP_ID);
-	diag_send_event_mask_update(driver->ch_wcnss_cntl,
-						 diag_event_num_bytes);
-}
-
-void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
-{
-	void *buf = driver->buf_log_mask_update;
-	int header_size = sizeof(struct diag_ctrl_log_mask);
-	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
-	int i, size, wr_size = -ENOMEM, retry_count = 0, timer;
-
-	mutex_lock(&driver->diag_cntl_mutex);
-	for (i = 0; i < MAX_EQUIP_ID; i++) {
-		size = (ptr->num_items+7)/8;
-		/* reached null entry */
-		if ((ptr->equip_id == 0) && (ptr->index == 0))
-			break;
-		driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
-		driver->log_mask->num_items = ptr->num_items;
-		driver->log_mask->data_len  = 11 + size;
-		driver->log_mask->stream_id = 1; /* 2, if dual stream */
-		driver->log_mask->status = 3; /* status for valid mask */
-		driver->log_mask->equip_id = ptr->equip_id;
-		driver->log_mask->log_mask_size = size;
-		/* send only desired update, NOT ALL */
-		if (equip_id == ALL_EQUIP_ID || equip_id ==
-					 driver->log_mask->equip_id) {
-			memcpy(buf, driver->log_mask, header_size);
-			memcpy(buf+header_size, driver->log_masks+ptr->index,
-									 size);
-			if (ch) {
-				while (retry_count < 3) {
-					wr_size = smd_write(ch, buf,
-							 header_size + size);
-					if (wr_size == -ENOMEM) {
-						retry_count++;
-						for (timer = 0; timer < 5;
-								 timer++)
-							udelay(2000);
-					} else
-						break;
-				}
-				if (wr_size != header_size + size)
-					pr_err("diag: log mask update failed"
-				 " %d, tried %d", wr_size, header_size + size);
-				else
-					pr_debug("diag: updated log equip ID %d"
-					",len %d\n", driver->log_mask->equip_id,
-					 driver->log_mask->log_mask_size);
-			} else
-				pr_err("diag: ch not valid for log update\n");
-		}
-		ptr++;
-	}
-	mutex_unlock(&driver->diag_cntl_mutex);
-}
-
-void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
-{
-	void *buf = driver->buf_event_mask_update;
-	int header_size = sizeof(struct diag_ctrl_event_mask);
-	int wr_size = -ENOMEM, retry_count = 0, timer;
-
-	mutex_lock(&driver->diag_cntl_mutex);
-	if (num_bytes == 0) {
-		pr_debug("diag: event mask not set yet, so no update\n");
-		mutex_unlock(&driver->diag_cntl_mutex);
-		return;
-	}
-	/* send event mask update */
-	driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
-	driver->event_mask->data_len = 7 + num_bytes;
-	driver->event_mask->stream_id = 1; /* 2, if dual stream */
-	driver->event_mask->status = 3; /* status for valid mask */
-	driver->event_mask->event_config = diag_event_config; /* event config */
-	driver->event_mask->event_mask_size = num_bytes;
-	memcpy(buf, driver->event_mask, header_size);
-	memcpy(buf+header_size, driver->event_masks, num_bytes);
-	if (ch) {
-		while (retry_count < 3) {
-			wr_size = smd_write(ch, buf, header_size + num_bytes);
-			if (wr_size == -ENOMEM) {
-				retry_count++;
-				for (timer = 0; timer < 5; timer++)
-					udelay(2000);
-			} else
-				break;
-		}
-		if (wr_size != header_size + num_bytes)
-			pr_err("diag: error writing event mask %d, tried %d\n",
-					 wr_size, header_size + num_bytes);
-	} else
-		pr_err("diag: ch not valid for event update\n");
-	mutex_unlock(&driver->diag_cntl_mutex);
-}
-
-void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
-						int updated_ssid_last, int proc)
-{
-	void *buf = driver->buf_msg_mask_update;
-	int first, last, actual_last, size = -ENOMEM, retry_count = 0, timer;
-	int header_size = sizeof(struct diag_ctrl_msg_mask);
-	uint8_t *ptr = driver->msg_masks;
-
-	mutex_lock(&driver->diag_cntl_mutex);
-	while (*(uint32_t *)(ptr + 4)) {
-		first = *(uint32_t *)ptr;
-		ptr += 4;
-		last = *(uint32_t *)ptr;
-		ptr += 4;
-		actual_last = *(uint32_t *)ptr;
-		ptr += 4;
-		if ((updated_ssid_first >= first && updated_ssid_last <=
-			 actual_last) || (updated_ssid_first == ALL_SSID)) {
-			/* send f3 mask update */
-			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
-			driver->msg_mask->msg_mask_size = actual_last -
-								 first + 1;
-			driver->msg_mask->data_len = 11 +
-					 4 * (driver->msg_mask->msg_mask_size);
-			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
-			driver->msg_mask->status = 3; /* status valid mask */
-			driver->msg_mask->msg_mode = 0; /* Legcay mode */
-			driver->msg_mask->ssid_first = first;
-			driver->msg_mask->ssid_last = actual_last;
-			memcpy(buf, driver->msg_mask, header_size);
-			memcpy(buf+header_size, ptr,
-				 4 * (driver->msg_mask->msg_mask_size));
-			if (ch) {
-				while (retry_count < 3) {
-					size = smd_write(ch, buf, header_size +
-					 4*(driver->msg_mask->msg_mask_size));
-					if (size == -ENOMEM) {
-						retry_count++;
-						for (timer = 0; timer < 5;
-								 timer++)
-							udelay(2000);
-					} else
-						break;
-				}
-				if (size != header_size +
-					 4*(driver->msg_mask->msg_mask_size))
-					pr_err("diag: proc %d, msg mask update "
-	 "fail %d, tried %d\n", proc, size,
-	 header_size + 4*(driver->msg_mask->msg_mask_size));
-				else
-					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
-						first, actual_last, proc);
-			} else
-				pr_err("diag: proc %d, ch invalid msg mask"
-						 "update\n", proc);
-		}
-		ptr += MAX_SSID_PER_RANGE*4;
-	}
-	mutex_unlock(&driver->diag_cntl_mutex);
-}
-
 static int diag_process_apps_pkt(unsigned char *buf, int len)
 {
 	uint16_t subsys_cmd_code;
 	int subsys_id, ssid_first, ssid_last, ssid_range;
 	int packet_type = 1, i, cmd_code;
-	int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
 	unsigned char *temp = buf;
-	uint8_t *rt_mask_ptr;
-	int data_type, equip_id, num_items;
+	int data_type;
 #if defined(CONFIG_DIAG_OVER_USB)
-	int payload_length;
 	unsigned char *ptr;
 #endif
 
-	/* Set log masks */
-	if (*buf == 0x73 && *(int *)(buf+4) == 3) {
-		buf += 8;
-		/* Read Equip ID and pass as first param below*/
-		diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
-		diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (chk_apps_only()) {
-			driver->apps_rsp_buf[0] = 0x73;
-			*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
-			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
-			payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
-			for (i = 0; i < payload_length; i++)
-				*(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
-			if (driver->ch_cntl)
-				diag_send_log_mask_update(driver->ch_cntl,
-								 *(int *)buf);
-			if (driver->chlpass_cntl)
-				diag_send_log_mask_update(driver->chlpass_cntl,
-								 *(int *)buf);
-			if (driver->ch_wcnss_cntl)
-				diag_send_log_mask_update(driver->ch_wcnss_cntl,
-								 *(int *)buf);
-			ENCODE_RSP_AND_SEND(12 + payload_length - 1);
-			return 0;
-		} else
-			buf = temp;
-#endif
-	} /* Get log masks */
-	else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (!(driver->ch) && chk_apps_only()) {
-			equip_id = *(int *)(buf + 8);
-			num_items = *(int *)(buf + 12);
-			driver->apps_rsp_buf[0] = 0x73;
-			driver->apps_rsp_buf[1] = 0x0;
-			driver->apps_rsp_buf[2] = 0x0;
-			driver->apps_rsp_buf[3] = 0x0;
-			*(int *)(driver->apps_rsp_buf + 4) = 0x4;
-			if (!chk_equip_id_and_mask(equip_id,
-						 driver->apps_rsp_buf+20))
-				*(int *)(driver->apps_rsp_buf + 8) = 0x0;
-			else
-				*(int *)(driver->apps_rsp_buf + 8) = 0x1;
-			*(int *)(driver->apps_rsp_buf + 12) = equip_id;
-			*(int *)(driver->apps_rsp_buf + 16) = num_items;
-			ENCODE_RSP_AND_SEND(20+(num_items+7)/8-1);
-			return 0;
-		} else
-			buf = temp;
-#endif
-	} /* Disable log masks */
-	else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
-		/* Disable mask for each log code */
-		diag_disable_log_mask();
-		diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (chk_apps_only()) {
-			driver->apps_rsp_buf[0] = 0x73;
-			driver->apps_rsp_buf[1] = 0x0;
-			driver->apps_rsp_buf[2] = 0x0;
-			driver->apps_rsp_buf[3] = 0x0;
-			*(int *)(driver->apps_rsp_buf + 4) = 0x0;
-			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
-			if (driver->ch_cntl)
-				diag_send_log_mask_update(driver->ch_cntl,
-								 ALL_EQUIP_ID);
-			if (driver->chlpass_cntl)
-				diag_send_log_mask_update(driver->chlpass_cntl,
-								 ALL_EQUIP_ID);
-			if (driver->ch_wcnss_cntl)
-				diag_send_log_mask_update(driver->ch_wcnss_cntl,
-								 ALL_EQUIP_ID);
-			ENCODE_RSP_AND_SEND(11);
-			return 0;
-		}
-#endif
-	} /* Get runtime message mask  */
-	else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
-		ssid_first = *(uint16_t *)(buf + 2);
-		ssid_last = *(uint16_t *)(buf + 4);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (!(driver->ch) && chk_apps_only()) {
-			driver->apps_rsp_buf[0] = 0x7d;
-			driver->apps_rsp_buf[1] = 0x3;
-			*(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
-			*(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
-			driver->apps_rsp_buf[6] = 0x1; /* Success Status */
-			driver->apps_rsp_buf[7] = 0x0;
-			rt_mask_ptr = driver->msg_masks;
-			while (*(uint32_t *)(rt_mask_ptr + 4)) {
-				rt_first_ssid = *(uint32_t *)rt_mask_ptr;
-				rt_mask_ptr += 8; /* +8 to skip 'last' */
-				rt_last_ssid = *(uint32_t *)rt_mask_ptr;
-				rt_mask_ptr += 4;
-				if (ssid_first == rt_first_ssid && ssid_last ==
-								 rt_last_ssid) {
-					rt_mask_size = 4 * (rt_last_ssid -
-							 rt_first_ssid + 1);
-					memcpy(driver->apps_rsp_buf+8,
-						 rt_mask_ptr, rt_mask_size);
-					ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
-					return 0;
-				}
-				rt_mask_ptr += MAX_SSID_PER_RANGE*4;
-			}
-		} else
-			buf = temp;
-#endif
-	} /* Set runtime message mask  */
-	else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
-		ssid_first = *(uint16_t *)(buf + 2);
-		ssid_last = *(uint16_t *)(buf + 4);
-		ssid_range = 4 * (ssid_last - ssid_first + 1);
-		pr_debug("diag: received mask update for ssid_first = %d,"
-				" ssid_last = %d", ssid_first, ssid_last);
-		diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
-		diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (chk_apps_only()) {
-			for (i = 0; i < 8 + ssid_range; i++)
-				*(driver->apps_rsp_buf + i) = *(buf+i);
-			*(driver->apps_rsp_buf + 6) = 0x1;
-			if (driver->ch_cntl)
-				diag_send_msg_mask_update(driver->ch_cntl,
-					 ssid_first, ssid_last, MODEM_PROC);
-			if (driver->chlpass_cntl)
-				diag_send_msg_mask_update(driver->chlpass_cntl,
-					 ssid_first, ssid_last, LPASS_PROC);
-			if (driver->ch_wcnss_cntl)
-				diag_send_msg_mask_update(driver->ch_wcnss_cntl,
-					 ssid_first, ssid_last, WCNSS_PROC);
-			ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
-			return 0;
-		} else
-			buf = temp;
-#endif
-	} /* Set ALL runtime message mask  */
-	else if ((*buf == 0x7d) && (*(buf+1) == 0x5)) {
-		rt_mask = *(int *)(buf + 4);
-		diag_set_msg_mask(rt_mask);
-		diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (chk_apps_only()) {
-			driver->apps_rsp_buf[0] = 0x7d; /* cmd_code */
-			driver->apps_rsp_buf[1] = 0x5; /* set subcommand */
-			driver->apps_rsp_buf[2] = 1; /* success */
-			driver->apps_rsp_buf[3] = 0; /* rsvd */
-			*(int *)(driver->apps_rsp_buf + 4) = rt_mask;
-			/* send msg mask update to peripheral */
-			if (driver->ch_cntl)
-				diag_send_msg_mask_update(driver->ch_cntl,
-					 ALL_SSID, ALL_SSID, MODEM_PROC);
-			if (driver->chlpass_cntl)
-				diag_send_msg_mask_update(driver->chlpass_cntl,
-					 ALL_SSID, ALL_SSID, LPASS_PROC);
-			if (driver->ch_wcnss_cntl)
-				diag_send_msg_mask_update(driver->ch_wcnss_cntl,
-					 ALL_SSID, ALL_SSID, WCNSS_PROC);
-			ENCODE_RSP_AND_SEND(7);
-			return 0;
-		} else
-			buf = temp;
-#endif
-	} else if (*buf == 0x82) {	/* event mask change */
-		buf += 4;
-		diag_event_num_bytes =  (*(uint16_t *)buf)/8+1;
-		diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
-		diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (chk_apps_only()) {
-			driver->apps_rsp_buf[0] = 0x82;
-			driver->apps_rsp_buf[1] = 0x0;
-			*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
-			*(uint16_t *)(driver->apps_rsp_buf + 4) =
-							EVENT_LAST_ID + 1;
-			memcpy(driver->apps_rsp_buf+6, driver->event_masks,
-							 EVENT_LAST_ID/8+1);
-			if (driver->ch_cntl)
-				diag_send_event_mask_update(driver->ch_cntl,
-							 diag_event_num_bytes);
-			if (driver->chlpass_cntl)
-				diag_send_event_mask_update(
-						driver->chlpass_cntl,
-						diag_event_num_bytes);
-			if (driver->ch_wcnss_cntl)
-				diag_send_event_mask_update(
-				driver->ch_wcnss_cntl, diag_event_num_bytes);
-			ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
-			return 0;
-		} else
-			buf = temp;
-#endif
-	} else if (*buf == 0x60) {
-		diag_event_config = *(buf+1);
-		diag_toggle_event_mask(*(buf+1));
-		diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (chk_apps_only()) {
-			driver->apps_rsp_buf[0] = 0x60;
-			driver->apps_rsp_buf[1] = 0x0;
-			driver->apps_rsp_buf[2] = 0x0;
-			if (driver->ch_cntl)
-				diag_send_event_mask_update(driver->ch_cntl,
-							 diag_event_num_bytes);
-			if (driver->chlpass_cntl)
-				diag_send_event_mask_update(
-						driver->chlpass_cntl,
-						diag_event_num_bytes);
-			if (driver->ch_wcnss_cntl)
-				diag_send_event_mask_update(
-				driver->ch_wcnss_cntl, diag_event_num_bytes);
-			ENCODE_RSP_AND_SEND(2);
-			return 0;
-		}
-#endif
-	}
+	/* Check if the command is a supported mask command */
+	if (diag_process_apps_masks(buf, len) == 0)
+		return 0;
+
 	/* Check for registered clients and forward packet to apropriate proc */
 	cmd_code = (int)(*(char *)buf);
 	temp++;
@@ -1334,7 +675,7 @@
 		for (i = 0; i < 4; i++)
 			*(driver->apps_rsp_buf+i) = *(buf+i);
 		*(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
-		ENCODE_RSP_AND_SEND(7);
+		encode_rsp_and_send(7);
 		return 0;
 	}
 	/* Check for Apps Only & get event mask request */
@@ -1345,7 +686,7 @@
 		*(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
 		for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
 			*(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
-		ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
+		encode_rsp_and_send(6 + EVENT_LAST_ID/8);
 		return 0;
 	}
 	/* Get log ID range & Check for Apps Only */
@@ -1370,7 +711,7 @@
 		*(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
 		*(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
 		*(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
-		ENCODE_RSP_AND_SEND(75);
+		encode_rsp_and_send(75);
 		return 0;
 	}
 	/* Respond to Get SSID Range request message */
@@ -1428,7 +769,7 @@
 		*(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
 		*(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
 		*(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
-		ENCODE_RSP_AND_SEND(99);
+		encode_rsp_and_send(99);
 		return 0;
 	}
 	/* Check for Apps Only Respond to Get Subsys Build mask */
@@ -1540,14 +881,14 @@
 				*(int *)(ptr + i) = msg_bld_masks_22[i/4];
 			break;
 		}
-		ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
+		encode_rsp_and_send(8 + ssid_range - 1);
 		return 0;
 	}
 	/* Check for download command */
 	else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
 		/* send response back */
 		driver->apps_rsp_buf[0] = *buf;
-		ENCODE_RSP_AND_SEND(0);
+		encode_rsp_and_send(0);
 		msleep(5000);
 		/* call download API */
 		msm_set_restart_mode(RESTART_DLOAD);
@@ -1567,7 +908,7 @@
 			for (i = 0; i < 13; i++)
 				driver->apps_rsp_buf[i+3] = 0;
 
-			ENCODE_RSP_AND_SEND(15);
+			encode_rsp_and_send(15);
 			return 0;
 		}
 	}
@@ -1578,7 +919,7 @@
 			for (i = 0; i < 55; i++)
 				driver->apps_rsp_buf[i] = 0;
 
-			ENCODE_RSP_AND_SEND(54);
+			encode_rsp_and_send(54);
 			return 0;
 		}
 		/* respond to 0x7c command */
@@ -1591,12 +932,12 @@
 							 chk_config_get_id();
 			*(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
 			*(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
-			ENCODE_RSP_AND_SEND(13);
+			encode_rsp_and_send(13);
 			return 0;
 		}
 	}
 #endif
-		return packet_type;
+	return packet_type;
 }
 
 #ifdef CONFIG_DIAG_OVER_USB
@@ -1611,7 +952,7 @@
 	driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
 	for (i = 0; i < index; i++)
 		driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
-	ENCODE_RSP_AND_SEND(index - 3);
+	encode_rsp_and_send(index - 3);
 }
 #else
 static inline void diag_send_error_rsp(int index) {}
@@ -1994,27 +1335,6 @@
 	driver->use_device_tree = has_device_tree();
 	mutex_init(&driver->diag_cntl_mutex);
 
-	if (driver->event_mask == NULL) {
-		driver->event_mask = kzalloc(sizeof(
-			struct diag_ctrl_event_mask), GFP_KERNEL);
-		if (driver->event_mask == NULL)
-			goto err;
-		kmemleak_not_leak(driver->event_mask);
-	}
-	if (driver->msg_mask == NULL) {
-		driver->msg_mask = kzalloc(sizeof(
-			struct diag_ctrl_msg_mask), GFP_KERNEL);
-		if (driver->msg_mask == NULL)
-			goto err;
-		kmemleak_not_leak(driver->msg_mask);
-	}
-	if (driver->log_mask == NULL) {
-		driver->log_mask = kzalloc(sizeof(
-			struct diag_ctrl_log_mask), GFP_KERNEL);
-		if (driver->log_mask == NULL)
-			goto err;
-		kmemleak_not_leak(driver->log_mask);
-	}
 	if (driver->buf_in_1 == NULL) {
 		driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_1 == NULL)
@@ -2051,28 +1371,6 @@
 			goto err;
 		kmemleak_not_leak(driver->buf_in_wcnss_2);
 	}
-
-	if (driver->buf_msg_mask_update == NULL) {
-		driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
-								 GFP_KERNEL);
-		if (driver->buf_msg_mask_update == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_msg_mask_update);
-	}
-	if (driver->buf_log_mask_update == NULL) {
-		driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
-								 GFP_KERNEL);
-		if (driver->buf_log_mask_update == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_log_mask_update);
-	}
-	if (driver->buf_event_mask_update == NULL) {
-		driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
-								 GFP_KERNEL);
-		if (driver->buf_event_mask_update == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_event_mask_update);
-	}
 	if (driver->usb_buf_out  == NULL &&
 	     (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
 					 GFP_KERNEL)) == NULL)
@@ -2087,23 +1385,6 @@
 		if (driver->user_space_data == NULL)
 			goto err;
 	kmemleak_not_leak(driver->user_space_data);
-	if (driver->msg_masks == NULL
-	    && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
-					     GFP_KERNEL)) == NULL)
-		goto err;
-	kmemleak_not_leak(driver->msg_masks);
-	diag_create_msg_mask_table();
-	diag_event_num_bytes = 0;
-	if (driver->log_masks == NULL &&
-	    (driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL)) == NULL)
-		goto err;
-	kmemleak_not_leak(driver->log_masks);
-	driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
-	if (driver->event_masks == NULL &&
-	    (driver->event_masks = kzalloc(EVENT_MASK_SIZE,
-					    GFP_KERNEL)) == NULL)
-		goto err;
-	kmemleak_not_leak(driver->event_masks);
 	if (driver->client_map == NULL &&
 	    (driver->client_map = kzalloc
 	     ((driver->num_clients) * sizeof(struct diag_client_map),
@@ -2192,12 +1473,6 @@
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
 	INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
-	INIT_WORK(&(driver->diag_modem_mask_update_work),
-						 diag_modem_mask_update_fn);
-	INIT_WORK(&(driver->diag_lpass_mask_update_work),
-						 diag_lpass_mask_update_fn);
-	INIT_WORK(&(driver->diag_wcnss_mask_update_work),
-						 diag_wcnss_mask_update_fn);
 	driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
 			diag_usb_legacy_notifier);
 	if (IS_ERR(driver->legacy_ch)) {
@@ -2210,40 +1485,34 @@
 
 	return;
 err:
-		pr_err("diag: Could not initialize diag buffers");
-		kfree(driver->event_mask);
-		kfree(driver->log_mask);
-		kfree(driver->msg_mask);
-		kfree(driver->buf_in_1);
-		kfree(driver->buf_in_2);
-		kfree(driver->buf_in_lpass_1);
-		kfree(driver->buf_in_lpass_2);
-		kfree(driver->buf_in_wcnss_1);
-		kfree(driver->buf_in_wcnss_2);
-		kfree(driver->buf_msg_mask_update);
-		kfree(driver->buf_log_mask_update);
-		kfree(driver->buf_event_mask_update);
-		kfree(driver->usb_buf_out);
-		kfree(driver->hdlc_buf);
-		kfree(driver->msg_masks);
-		kfree(driver->log_masks);
-		kfree(driver->event_masks);
-		kfree(driver->client_map);
-		kfree(driver->buf_tbl);
-		kfree(driver->data_ready);
-		kfree(driver->table);
-		kfree(driver->pkt_buf);
-		kfree(driver->write_ptr_1);
-		kfree(driver->write_ptr_2);
-		kfree(driver->write_ptr_lpass_1);
-		kfree(driver->write_ptr_lpass_2);
-		kfree(driver->write_ptr_wcnss_1);
-		kfree(driver->write_ptr_wcnss_2);
-		kfree(driver->usb_read_ptr);
-		kfree(driver->apps_rsp_buf);
-		kfree(driver->user_space_data);
-		if (driver->diag_wq)
-			destroy_workqueue(driver->diag_wq);
+	pr_err("diag: Could not initialize diag buffers");
+	kfree(driver->buf_in_1);
+	kfree(driver->buf_in_2);
+	kfree(driver->buf_in_lpass_1);
+	kfree(driver->buf_in_lpass_2);
+	kfree(driver->buf_in_wcnss_1);
+	kfree(driver->buf_in_wcnss_2);
+	kfree(driver->buf_msg_mask_update);
+	kfree(driver->buf_log_mask_update);
+	kfree(driver->buf_event_mask_update);
+	kfree(driver->usb_buf_out);
+	kfree(driver->hdlc_buf);
+	kfree(driver->client_map);
+	kfree(driver->buf_tbl);
+	kfree(driver->data_ready);
+	kfree(driver->table);
+	kfree(driver->pkt_buf);
+	kfree(driver->write_ptr_1);
+	kfree(driver->write_ptr_2);
+	kfree(driver->write_ptr_lpass_1);
+	kfree(driver->write_ptr_lpass_2);
+	kfree(driver->write_ptr_wcnss_1);
+	kfree(driver->write_ptr_wcnss_2);
+	kfree(driver->usb_read_ptr);
+	kfree(driver->apps_rsp_buf);
+	kfree(driver->user_space_data);
+	if (driver->diag_wq)
+		destroy_workqueue(driver->diag_wq);
 }
 
 void diagfwd_exit(void)
@@ -2262,9 +1531,6 @@
 	platform_driver_unregister(&msm_smd_ch1_driver);
 	platform_driver_unregister(&msm_diag_dci_driver);
 	platform_driver_unregister(&diag_smd_lite_driver);
-	kfree(driver->event_mask);
-	kfree(driver->log_mask);
-	kfree(driver->msg_mask);
 	kfree(driver->buf_in_1);
 	kfree(driver->buf_in_2);
 	kfree(driver->buf_in_lpass_1);
@@ -2276,9 +1542,6 @@
 	kfree(driver->buf_event_mask_update);
 	kfree(driver->usb_buf_out);
 	kfree(driver->hdlc_buf);
-	kfree(driver->msg_masks);
-	kfree(driver->log_masks);
-	kfree(driver->event_masks);
 	kfree(driver->client_map);
 	kfree(driver->buf_tbl);
 	kfree(driver->data_ready);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index cf7fda6..a0631d6 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -16,6 +16,9 @@
 #define NO_PROCESS	0
 #define NON_APPS_PROC	-1
 
+#define CHK_OVERFLOW(bufStart, start, end, length) \
+	((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
+
 void diagfwd_init(void);
 void diagfwd_exit(void);
 void diag_process_hdlc(void *data, unsigned len);
@@ -31,11 +34,9 @@
 int chk_apps_only(void);
 int chk_apps_master(void);
 int chk_polling_response(void);
-void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
-void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
-					 int ssid_last, int proc);
-void diag_send_log_mask_update(smd_channel_t *, int);
+void diag_update_userspace_clients(unsigned int type);
 void diag_update_sleeping_process(int process_id, int data_type);
+void encode_rsp_and_send(int buf_length);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
@@ -43,6 +44,5 @@
 #endif
 extern int diag_debug_buf_idx;
 extern unsigned char diag_debug_buf[1024];
-extern int diag_event_num_bytes;
 extern struct platform_driver msm_diag_dci_driver;
 #endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 9fc1164..4848a1d 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -17,9 +17,6 @@
 #include "diagchar.h"
 #include "diagfwd.h"
 #include "diagfwd_cntl.h"
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#endif
 /* tracks which peripheral is undergoing SSR */
 static uint16_t reg_dirty;
 #define HDR_SIZ 8
@@ -221,6 +218,8 @@
 					pr_err("diag: drop reg proc %d\n",
 								 proc_num);
 				kfree(temp);
+			} else if (type != DIAG_CTRL_MSG_REG) {
+				flag = 1;
 			}
 			buf = buf + HDR_SIZ + data_len;
 		}
@@ -363,291 +362,3 @@
 	kfree(driver->buf_in_lpass_cntl);
 	kfree(driver->buf_in_wcnss_cntl);
 }
-
-#ifdef CONFIG_DEBUG_FS
-#define DEBUG_BUF_SIZE	4096
-static struct dentry *diag_dbgfs_dent;
-static int diag_dbgfs_table_index;
-
-static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
-				      size_t count, loff_t *ppos)
-{
-	char *buf;
-	int ret;
-
-	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
-	if (!buf) {
-		pr_err("diag: %s, Error allocating memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
-		"modem ch: 0x%x\n"
-		"lpass ch: 0x%x\n"
-		"riva ch: 0x%x\n"
-		"dci ch: 0x%x\n"
-		"modem cntl_ch: 0x%x\n"
-		"lpass cntl_ch: 0x%x\n"
-		"riva cntl_ch: 0x%x\n"
-		"CPU Tools id: %d\n"
-		"Apps only: %d\n"
-		"Apps master: %d\n"
-		"Check Polling Response: %d\n"
-		"polling_reg_flag: %d\n"
-		"uses device tree: %d\n"
-		"in_busy_1: %d\n"
-		"in_busy_2: %d\n"
-		"in_busy_lpass_1: %d\n"
-		"in_busy_lpass_2: %d\n"
-		"in_busy_wcnss_1: %d\n"
-		"in_busy_wcnss_2: %d\n"
-		"in_busy_dci: %d\n"
-		"logging_mode: %d\n",
-		(unsigned int)driver->ch,
-		(unsigned int)driver->chlpass,
-		(unsigned int)driver->ch_wcnss,
-		(unsigned int)driver->ch_dci,
-		(unsigned int)driver->ch_cntl,
-		(unsigned int)driver->chlpass_cntl,
-		(unsigned int)driver->ch_wcnss_cntl,
-		chk_config_get_id(),
-		chk_apps_only(),
-		chk_apps_master(),
-		chk_polling_response(),
-		driver->polling_reg_flag,
-		driver->use_device_tree,
-		driver->in_busy_1,
-		driver->in_busy_2,
-		driver->in_busy_lpass_1,
-		driver->in_busy_lpass_2,
-		driver->in_busy_wcnss_1,
-		driver->in_busy_wcnss_2,
-		driver->in_busy_dci,
-		driver->logging_mode);
-
-#ifdef CONFIG_DIAG_OVER_USB
-	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
-		"usb_connected: %d\n",
-		driver->usb_connected);
-#endif
-	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
-
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t diag_dbgfs_read_workpending(struct file *file,
-				char __user *ubuf, size_t count, loff_t *ppos)
-{
-	char *buf;
-	int ret;
-
-	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
-	if (!buf) {
-		pr_err("diag: %s, Error allocating memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
-		"Pending status for work_stucts:\n"
-		"diag_drain_work: %d\n"
-		"diag_read_smd_work: %d\n"
-		"diag_read_smd_cntl_work: %d\n"
-		"diag_read_smd_lpass_work: %d\n"
-		"diag_read_smd_lpass_cntl_work: %d\n"
-		"diag_read_smd_wcnss_work: %d\n"
-		"diag_read_smd_wcnss_cntl_work: %d\n"
-		"diag_modem_mask_update_work: %d\n"
-		"diag_lpass_mask_update_work: %d\n"
-		"diag_wcnss_mask_update_work: %d\n"
-		"diag_read_smd_dci_work: %d\n",
-		work_pending(&(driver->diag_drain_work)),
-		work_pending(&(driver->diag_read_smd_work)),
-		work_pending(&(driver->diag_read_smd_cntl_work)),
-		work_pending(&(driver->diag_read_smd_lpass_work)),
-		work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
-		work_pending(&(driver->diag_read_smd_wcnss_work)),
-		work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
-		work_pending(&(driver->diag_modem_mask_update_work)),
-		work_pending(&(driver->diag_lpass_mask_update_work)),
-		work_pending(&(driver->diag_wcnss_mask_update_work)),
-		work_pending(&(driver->diag_read_smd_dci_work)));
-
-#ifdef CONFIG_DIAG_OVER_USB
-	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
-		"diag_proc_hdlc_work: %d\n"
-		"diag_read_work: %d\n",
-		work_pending(&(driver->diag_proc_hdlc_work)),
-		work_pending(&(driver->diag_read_work)));
-#endif
-	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
-
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
-				     size_t count, loff_t *ppos)
-{
-	char *buf;
-	int ret = 0;
-	int i;
-	int bytes_remaining;
-	int bytes_in_buffer = 0;
-	int bytes_written;
-	int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
-
-	if (diag_dbgfs_table_index >= diag_max_reg) {
-		/* Done. Reset to prepare for future requests */
-		diag_dbgfs_table_index = 0;
-		return 0;
-	}
-
-	buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
-	if (!buf) {
-		pr_err("diag: %s, Error allocating memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	bytes_remaining = buf_size;
-	for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
-		/* Do not process empty entries in the table */
-		if (driver->table[i].process_id == 0)
-			continue;
-
-		bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
-			"i: %3d, cmd_code: %4x, subsys_id: %4x, "
-			"client: %2d, cmd_code_lo: %4x, "
-			"cmd_code_hi: %4x, process_id: %5d\n",
-			i,
-			driver->table[i].cmd_code,
-			driver->table[i].subsys_id,
-			driver->table[i].client_id,
-			driver->table[i].cmd_code_lo,
-			driver->table[i].cmd_code_hi,
-			driver->table[i].process_id);
-
-		bytes_in_buffer += bytes_written;
-
-		/* Check if there is room to add another table entry */
-		bytes_remaining = buf_size - bytes_in_buffer;
-		if (bytes_remaining < bytes_written)
-			break;
-	}
-	diag_dbgfs_table_index = i;
-
-	*ppos = 0;
-	ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
-
-	kfree(buf);
-	return ret;
-}
-
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
-				    size_t count, loff_t *ppos)
-{
-	char *buf;
-	int ret;
-
-	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
-	if (!buf) {
-		pr_err("diag: %s, Error allocating memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
-		"hsic ch: %d\n"
-		"hsic_inited: %d\n"
-		"hsic enabled: %d\n"
-		"hsic_opened: %d\n"
-		"hsic_suspend: %d\n"
-		"in_busy_hsic_read_on_device: %d\n"
-		"in_busy_hsic_write: %d\n"
-		"count_hsic_pool: %d\n"
-		"count_hsic_write_pool: %d\n"
-		"diag_hsic_pool: %x\n"
-		"diag_hsic_write_pool: %x\n"
-		"write_len_mdm: %d\n"
-		"num_hsic_buf_tbl_entries: %d\n"
-		"usb_mdm_connected: %d\n"
-		"diag_read_mdm_work: %d\n"
-		"diag_read_hsic_work: %d\n"
-		"diag_disconnect_work: %d\n"
-		"diag_usb_read_complete_work: %d\n",
-		driver->hsic_ch,
-		driver->hsic_inited,
-		driver->hsic_device_enabled,
-		driver->hsic_device_opened,
-		driver->hsic_suspend,
-		driver->in_busy_hsic_read_on_device,
-		driver->in_busy_hsic_write,
-		driver->count_hsic_pool,
-		driver->count_hsic_write_pool,
-		(unsigned int)driver->diag_hsic_pool,
-		(unsigned int)driver->diag_hsic_write_pool,
-		driver->write_len_mdm,
-		driver->num_hsic_buf_tbl_entries,
-		driver->usb_mdm_connected,
-		work_pending(&(driver->diag_read_mdm_work)),
-		work_pending(&(driver->diag_read_hsic_work)),
-		work_pending(&(driver->diag_disconnect_work)),
-		work_pending(&(driver->diag_usb_read_complete_work)));
-
-	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
-
-	kfree(buf);
-	return ret;
-}
-
-const struct file_operations diag_dbgfs_hsic_ops = {
-	.read = diag_dbgfs_read_hsic,
-};
-#endif
-
-const struct file_operations diag_dbgfs_status_ops = {
-	.read = diag_dbgfs_read_status,
-};
-
-const struct file_operations diag_dbgfs_table_ops = {
-	.read = diag_dbgfs_read_table,
-};
-
-const struct file_operations diag_dbgfs_workpending_ops = {
-	.read = diag_dbgfs_read_workpending,
-};
-
-void diag_debugfs_init(void)
-{
-	diag_dbgfs_dent = debugfs_create_dir("diag", 0);
-	if (IS_ERR(diag_dbgfs_dent))
-		return;
-
-	debugfs_create_file("status", 0444, diag_dbgfs_dent, 0,
-		&diag_dbgfs_status_ops);
-
-	debugfs_create_file("table", 0444, diag_dbgfs_dent, 0,
-		&diag_dbgfs_table_ops);
-
-	debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
-		&diag_dbgfs_workpending_ops);
-
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-	debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
-		&diag_dbgfs_hsic_ops);
-#endif
-
-	diag_dbgfs_table_index = 0;
-}
-
-void diag_debugfs_cleanup(void)
-{
-	if (diag_dbgfs_dent) {
-		debugfs_remove_recursive(diag_dbgfs_dent);
-		diag_dbgfs_dent = NULL;
-	}
-}
-#else
-void diag_debugfs_init(void) { }
-void diag_debugfs_cleanup(void) { }
-#endif
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index e6f5352..8a0ec3f 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -88,7 +88,5 @@
 void diag_clean_modem_reg_fn(struct work_struct *);
 void diag_clean_lpass_reg_fn(struct work_struct *);
 void diag_clean_wcnss_reg_fn(struct work_struct *);
-void diag_debugfs_init(void);
-void diag_debugfs_cleanup(void);
 
 #endif
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index a23fff0..ea4ad4f 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -31,6 +31,16 @@
 	  For production builds, you should probably say 'N' here to avoid
 	  potential power, performance and memory penalty.
 
+config MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE
+	bool "Turn on PC saving by default"
+	depends on MSM_QDSS
+	help
+	  Turns on program counter saving on reset by default. Otherwise,
+	  PC saving is disabled by default but can be enabled via sysfs.
+
+	  For production builds, you should probably say 'N' here to avoid
+	  potential power penalty.
+
 config CONTROL_TRACE
 	tristate "Turn on to control tracing"
 	help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index a2815de..033e5a0 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_CONTROL_TRACE) += control_trace.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
+obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o coresight-etm-cp14.o
diff --git a/drivers/coresight/coresight-etm-cp14.c b/drivers/coresight/coresight-etm-cp14.c
new file mode 100644
index 0000000..9a6c13a
--- /dev/null
+++ b/drivers/coresight/coresight-etm-cp14.c
@@ -0,0 +1,510 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <asm/hardware/cp14.h>
+
+static unsigned int etm_read_reg(uint32_t reg)
+{
+	switch (reg) {
+	case 0x0:
+		return etm_read(ETMCR);
+	case 0x1:
+		return etm_read(ETMCCR);
+	case 0x2:
+		return etm_read(ETMTRIGGER);
+	case 0x4:
+		return etm_read(ETMSR);
+	case 0x5:
+		return etm_read(ETMSCR);
+	case 0x6:
+		return etm_read(ETMTSSCR);
+	case 0x8:
+		return etm_read(ETMTEEVR);
+	case 0x9:
+		return etm_read(ETMTECR1);
+	case 0xB:
+		return etm_read(ETMFFLR);
+	case 0x10:
+		return etm_read(ETMACVR0);
+	case 0x11:
+		return etm_read(ETMACVR1);
+	case 0x12:
+		return etm_read(ETMACVR2);
+	case 0x13:
+		return etm_read(ETMACVR3);
+	case 0x14:
+		return etm_read(ETMACVR4);
+	case 0x15:
+		return etm_read(ETMACVR5);
+	case 0x16:
+		return etm_read(ETMACVR6);
+	case 0x17:
+		return etm_read(ETMACVR7);
+	case 0x18:
+		return etm_read(ETMACVR8);
+	case 0x19:
+		return etm_read(ETMACVR9);
+	case 0x1A:
+		return etm_read(ETMACVR10);
+	case 0x1B:
+		return etm_read(ETMACVR11);
+	case 0x1C:
+		return etm_read(ETMACVR12);
+	case 0x1D:
+		return etm_read(ETMACVR13);
+	case 0x1E:
+		return etm_read(ETMACVR14);
+	case 0x1F:
+		return etm_read(ETMACVR15);
+	case 0x20:
+		return etm_read(ETMACTR0);
+	case 0x21:
+		return etm_read(ETMACTR1);
+	case 0x22:
+		return etm_read(ETMACTR2);
+	case 0x23:
+		return etm_read(ETMACTR3);
+	case 0x24:
+		return etm_read(ETMACTR4);
+	case 0x25:
+		return etm_read(ETMACTR5);
+	case 0x26:
+		return etm_read(ETMACTR6);
+	case 0x27:
+		return etm_read(ETMACTR7);
+	case 0x28:
+		return etm_read(ETMACTR8);
+	case 0x29:
+		return etm_read(ETMACTR9);
+	case 0x2A:
+		return etm_read(ETMACTR10);
+	case 0x2B:
+		return etm_read(ETMACTR11);
+	case 0x2C:
+		return etm_read(ETMACTR12);
+	case 0x2D:
+		return etm_read(ETMACTR13);
+	case 0x2E:
+		return etm_read(ETMACTR14);
+	case 0x2F:
+		return etm_read(ETMACTR15);
+	case 0x50:
+		return etm_read(ETMCNTRLDVR0);
+	case 0x51:
+		return etm_read(ETMCNTRLDVR1);
+	case 0x52:
+		return etm_read(ETMCNTRLDVR2);
+	case 0x53:
+		return etm_read(ETMCNTRLDVR3);
+	case 0x54:
+		return etm_read(ETMCNTENR0);
+	case 0x55:
+		return etm_read(ETMCNTENR1);
+	case 0x56:
+		return etm_read(ETMCNTENR2);
+	case 0x57:
+		return etm_read(ETMCNTENR3);
+	case 0x58:
+		return etm_read(ETMCNTRLDEVR0);
+	case 0x59:
+		return etm_read(ETMCNTRLDEVR1);
+	case 0x5A:
+		return etm_read(ETMCNTRLDEVR2);
+	case 0x5B:
+		return etm_read(ETMCNTRLDEVR3);
+	case 0x5C:
+		return etm_read(ETMCNTVR0);
+	case 0x5D:
+		return etm_read(ETMCNTVR1);
+	case 0x5E:
+		return etm_read(ETMCNTVR2);
+	case 0x5F:
+		return etm_read(ETMCNTVR3);
+	case 0x60:
+		return etm_read(ETMSQ12EVR);
+	case 0x61:
+		return etm_read(ETMSQ21EVR);
+	case 0x62:
+		return etm_read(ETMSQ23EVR);
+	case 0x63:
+		return etm_read(ETMSQ31EVR);
+	case 0x64:
+		return etm_read(ETMSQ32EVR);
+	case 0x65:
+		return etm_read(ETMSQ13EVR);
+	case 0x67:
+		return etm_read(ETMSQR);
+	case 0x68:
+		return etm_read(ETMEXTOUTEVR0);
+	case 0x69:
+		return etm_read(ETMEXTOUTEVR1);
+	case 0x6A:
+		return etm_read(ETMEXTOUTEVR2);
+	case 0x6B:
+		return etm_read(ETMEXTOUTEVR3);
+	case 0x6C:
+		return etm_read(ETMCIDCVR0);
+	case 0x6D:
+		return etm_read(ETMCIDCVR1);
+	case 0x6E:
+		return etm_read(ETMCIDCVR2);
+	case 0x6F:
+		return etm_read(ETMCIDCMR);
+	case 0x70:
+		return etm_read(ETMIMPSPEC0);
+	case 0x71:
+		return etm_read(ETMIMPSPEC1);
+	case 0x72:
+		return etm_read(ETMIMPSPEC2);
+	case 0x73:
+		return etm_read(ETMIMPSPEC3);
+	case 0x74:
+		return etm_read(ETMIMPSPEC4);
+	case 0x75:
+		return etm_read(ETMIMPSPEC5);
+	case 0x76:
+		return etm_read(ETMIMPSPEC6);
+	case 0x77:
+		return etm_read(ETMIMPSPEC7);
+	case 0x78:
+		return etm_read(ETMSYNCFR);
+	case 0x79:
+		return etm_read(ETMIDR);
+	case 0x7A:
+		return etm_read(ETMCCER);
+	case 0x7B:
+		return etm_read(ETMEXTINSELR);
+	case 0x7C:
+		return etm_read(ETMTESSEICR);
+	case 0x7D:
+		return etm_read(ETMEIBCR);
+	case 0x7E:
+		return etm_read(ETMTSEVR);
+	case 0x7F:
+		return etm_read(ETMAUXCR);
+	case 0x80:
+		return etm_read(ETMTRACEIDR);
+	case 0x90:
+		return etm_read(ETMVMIDCVR);
+	case 0xC1:
+		return etm_read(ETMOSLSR);
+	case 0xC2:
+		return etm_read(ETMOSSRR);
+	case 0xC4:
+		return etm_read(ETMPDCR);
+	case 0xC5:
+		return etm_read(ETMPDSR);
+	default:
+		WARN(1, "invalid CP14 access to ETM reg: %lx",
+							(unsigned long)reg);
+		return 0;
+	}
+}
+
+static void etm_write_reg(uint32_t val, uint32_t reg)
+{
+	switch (reg) {
+	case 0x0:
+		etm_write(val, ETMCR);
+		return;
+	case 0x2:
+		etm_write(val, ETMTRIGGER);
+		return;
+	case 0x4:
+		etm_write(val, ETMSR);
+		return;
+	case 0x6:
+		etm_write(val, ETMTSSCR);
+		return;
+	case 0x8:
+		etm_write(val, ETMTEEVR);
+		return;
+	case 0x9:
+		etm_write(val, ETMTECR1);
+		return;
+	case 0xB:
+		etm_write(val, ETMFFLR);
+		return;
+	case 0x10:
+		etm_write(val, ETMACVR0);
+		return;
+	case 0x11:
+		etm_write(val, ETMACVR1);
+		return;
+	case 0x12:
+		etm_write(val, ETMACVR2);
+		return;
+	case 0x13:
+		etm_write(val, ETMACVR3);
+		return;
+	case 0x14:
+		etm_write(val, ETMACVR4);
+		return;
+	case 0x15:
+		etm_write(val, ETMACVR5);
+		return;
+	case 0x16:
+		etm_write(val, ETMACVR6);
+		return;
+	case 0x17:
+		etm_write(val, ETMACVR7);
+		return;
+	case 0x18:
+		etm_write(val, ETMACVR8);
+		return;
+	case 0x19:
+		etm_write(val, ETMACVR9);
+		return;
+	case 0x1A:
+		etm_write(val, ETMACVR10);
+		return;
+	case 0x1B:
+		etm_write(val, ETMACVR11);
+		return;
+	case 0x1C:
+		etm_write(val, ETMACVR12);
+		return;
+	case 0x1D:
+		etm_write(val, ETMACVR13);
+		return;
+	case 0x1E:
+		etm_write(val, ETMACVR14);
+		return;
+	case 0x1F:
+		etm_write(val, ETMACVR15);
+		return;
+	case 0x20:
+		etm_write(val, ETMACTR0);
+		return;
+	case 0x21:
+		etm_write(val, ETMACTR1);
+		return;
+	case 0x22:
+		etm_write(val, ETMACTR2);
+		return;
+	case 0x23:
+		etm_write(val, ETMACTR3);
+		return;
+	case 0x24:
+		etm_write(val, ETMACTR4);
+		return;
+	case 0x25:
+		etm_write(val, ETMACTR5);
+		return;
+	case 0x26:
+		etm_write(val, ETMACTR6);
+		return;
+	case 0x27:
+		etm_write(val, ETMACTR7);
+		return;
+	case 0x28:
+		etm_write(val, ETMACTR8);
+		return;
+	case 0x29:
+		etm_write(val, ETMACTR9);
+		return;
+	case 0x2A:
+		etm_write(val, ETMACTR10);
+		return;
+	case 0x2B:
+		etm_write(val, ETMACTR11);
+		return;
+	case 0x2C:
+		etm_write(val, ETMACTR12);
+		return;
+	case 0x2D:
+		etm_write(val, ETMACTR13);
+		return;
+	case 0x2E:
+		etm_write(val, ETMACTR14);
+		return;
+	case 0x2F:
+		etm_write(val, ETMACTR15);
+		return;
+	case 0x50:
+		etm_write(val, ETMCNTRLDVR0);
+		return;
+	case 0x51:
+		etm_write(val, ETMCNTRLDVR1);
+		return;
+	case 0x52:
+		etm_write(val, ETMCNTRLDVR2);
+		return;
+	case 0x53:
+		etm_write(val, ETMCNTRLDVR3);
+		return;
+	case 0x54:
+		etm_write(val, ETMCNTENR0);
+		return;
+	case 0x55:
+		etm_write(val, ETMCNTENR1);
+		return;
+	case 0x56:
+		etm_write(val, ETMCNTENR2);
+		return;
+	case 0x57:
+		etm_write(val, ETMCNTENR3);
+		return;
+	case 0x58:
+		etm_write(val, ETMCNTRLDEVR0);
+		return;
+	case 0x59:
+		etm_write(val, ETMCNTRLDEVR1);
+		return;
+	case 0x5A:
+		etm_write(val, ETMCNTRLDEVR2);
+		return;
+	case 0x5B:
+		etm_write(val, ETMCNTRLDEVR3);
+		return;
+	case 0x5C:
+		etm_write(val, ETMCNTVR0);
+		return;
+	case 0x5D:
+		etm_write(val, ETMCNTVR1);
+		return;
+	case 0x5E:
+		etm_write(val, ETMCNTVR2);
+		return;
+	case 0x5F:
+		etm_write(val, ETMCNTVR3);
+		return;
+	case 0x60:
+		etm_write(val, ETMSQ12EVR);
+		return;
+	case 0x61:
+		etm_write(val, ETMSQ21EVR);
+		return;
+	case 0x62:
+		etm_write(val, ETMSQ23EVR);
+		return;
+	case 0x63:
+		etm_write(val, ETMSQ31EVR);
+		return;
+	case 0x64:
+		etm_write(val, ETMSQ32EVR);
+		return;
+	case 0x65:
+		etm_write(val, ETMSQ13EVR);
+		return;
+	case 0x67:
+		etm_write(val, ETMSQR);
+		return;
+	case 0x68:
+		etm_write(val, ETMEXTOUTEVR0);
+		return;
+	case 0x69:
+		etm_write(val, ETMEXTOUTEVR1);
+		return;
+	case 0x6A:
+		etm_write(val, ETMEXTOUTEVR2);
+		return;
+	case 0x6B:
+		etm_write(val, ETMEXTOUTEVR3);
+		return;
+	case 0x6C:
+		etm_write(val, ETMCIDCVR0);
+		return;
+	case 0x6D:
+		etm_write(val, ETMCIDCVR1);
+		return;
+	case 0x6E:
+		etm_write(val, ETMCIDCVR2);
+		return;
+	case 0x6F:
+		etm_write(val, ETMCIDCMR);
+		return;
+	case 0x70:
+		etm_write(val, ETMIMPSPEC0);
+		return;
+	case 0x71:
+		etm_write(val, ETMIMPSPEC1);
+		return;
+	case 0x72:
+		etm_write(val, ETMIMPSPEC2);
+		return;
+	case 0x73:
+		etm_write(val, ETMIMPSPEC3);
+		return;
+	case 0x74:
+		etm_write(val, ETMIMPSPEC4);
+		return;
+	case 0x75:
+		etm_write(val, ETMIMPSPEC5);
+		return;
+	case 0x76:
+		etm_write(val, ETMIMPSPEC6);
+		return;
+	case 0x77:
+		etm_write(val, ETMIMPSPEC7);
+		return;
+	case 0x78:
+		etm_write(val, ETMSYNCFR);
+		return;
+	case 0x7B:
+		etm_write(val, ETMEXTINSELR);
+		return;
+	case 0x7C:
+		etm_write(val, ETMTESSEICR);
+		return;
+	case 0x7D:
+		etm_write(val, ETMEIBCR);
+		return;
+	case 0x7E:
+		etm_write(val, ETMTSEVR);
+		return;
+	case 0x7F:
+		etm_write(val, ETMAUXCR);
+		return;
+	case 0x80:
+		etm_write(val, ETMTRACEIDR);
+		return;
+	case 0x90:
+		etm_write(val, ETMVMIDCVR);
+		return;
+	case 0xC0:
+		etm_write(val, ETMOSLAR);
+		return;
+	case 0xC2:
+		etm_write(val, ETMOSSRR);
+		return;
+	case 0xC4:
+		etm_write(val, ETMPDCR);
+		return;
+	case 0xC5:
+		etm_write(val, ETMPDSR);
+		return;
+	default:
+		WARN(1, "invalid CP14 access to ETM reg: %lx",
+							(unsigned long)reg);
+		return;
+	}
+}
+
+static inline uint32_t offset_to_reg_num(uint32_t off)
+{
+	return off >> 2;
+}
+
+unsigned int etm_readl_cp14(uint32_t off)
+{
+	uint32_t reg = offset_to_reg_num(off);
+	return etm_read_reg(reg);
+}
+
+void etm_writel_cp14(uint32_t val, uint32_t off)
+{
+	uint32_t reg = offset_to_reg_num(off);
+	etm_write_reg(val, reg);
+}
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 427cd7d..50bae55 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -35,20 +35,45 @@
 
 #include "coresight-priv.h"
 
-#define etm_writel(drvdata, val, off)	\
+#define etm_writel_mm(drvdata, val, off)  \
 			__raw_writel((val), drvdata->base + off)
-#define etm_readl(drvdata, off)		\
+#define etm_readl_mm(drvdata, off)        \
 			__raw_readl(drvdata->base + off)
 
+#define etm_writel(drvdata, val, off)					\
+({									\
+	if (cpu_is_krait_v3())						\
+		etm_writel_cp14(val, off);				\
+	else								\
+		etm_writel_mm(drvdata, val, off);			\
+})
+#define etm_readl(drvdata, off)						\
+({									\
+	uint32_t val;							\
+	if (cpu_is_krait_v3())						\
+		val = etm_readl_cp14(off);				\
+	else								\
+		val = etm_readl_mm(drvdata, off);			\
+	val;								\
+})
+
 #define ETM_LOCK(drvdata)						\
 do {									\
+	/* recommended by spec to ensure ETM writes are committed prior
+	 * to resuming execution
+	 */								\
 	mb();								\
-	etm_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+	isb();								\
+	etm_writel_mm(drvdata, 0x0, CORESIGHT_LAR);			\
 } while (0)
 #define ETM_UNLOCK(drvdata)						\
 do {									\
-	etm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	etm_writel_mm(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	/* ensure unlock and any pending writes are committed prior to
+	 * programming ETM registers
+	 */								\
 	mb();								\
+	isb();								\
 } while (0)
 
 /*
@@ -152,6 +177,15 @@
 	boot_enable, boot_enable, int, S_IRUGO
 );
 
+#ifdef CONFIG_MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE
+static int boot_pcsave_enable = 1;
+#else
+static int boot_pcsave_enable;
+#endif
+module_param_named(
+	boot_pcsave_enable, boot_pcsave_enable, int, S_IRUGO
+);
+
 struct etm_drvdata {
 	void __iomem			*base;
 	struct device			*dev;
@@ -169,6 +203,7 @@
 	uint8_t				reset;
 	uint32_t			mode;
 	uint32_t			ctrl;
+	uint8_t				ctrl_pwrdwn;
 	uint32_t			trigger_event;
 	uint32_t			startstop_ctrl;
 	uint32_t			enable_event;
@@ -195,12 +230,16 @@
 	uint32_t			ctxid_mask;
 	uint32_t			sync_freq;
 	uint32_t			timestamp_event;
+	uint8_t				pdcr_pwrup;
+	bool				pcsave_impl;
+	bool				pcsave_enable;
 };
 
 static struct etm_drvdata *etm0drvdata;
 
-/* ETM clock is derived from the processor clock and gets enabled on a
- * logical OR of below items on Krait (pass2 onwards):
+/*
+ * ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Krait (v2 onwards):
  * 1.CPMR[ETMCLKEN] is 1
  * 2.ETMCR[PD] is 0
  * 3.ETMPDCR[PU] is 1
@@ -210,26 +249,56 @@
  * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
  * enables
  *
- * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
- * clock vote in the driver and the save-restore code uses 1. above
+ * We rely on 5. to be able to access ETMCR/ETMPDCR and then use 2./3. above
+ * for ETM clock vote in the driver and the save-restore code uses 1. above
  * for its vote
  */
+static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+
+	/* ensure pending cp14 accesses complete before setting pwrdwn */
+	mb();
+	isb();
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr |= BIT(0);
+	etm_writel(drvdata, etmcr, ETMCR);
+}
+
+static void etm_clr_pwrdwn(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr &= ~BIT(0);
+	etm_writel(drvdata, etmcr, ETMCR);
+	/* ensure pwrup completes before subsequent cp14 accesses */
+	mb();
+	isb();
+}
+
 static void etm_set_pwrup(struct etm_drvdata *drvdata)
 {
 	uint32_t etmpdcr;
 
-	etmpdcr = etm_readl(drvdata, ETMPDCR);
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
 	etmpdcr |= BIT(3);
-	etm_writel(drvdata, etmpdcr, ETMPDCR);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+	/* ensure pwrup completes before subsequent cp14 accesses */
+	mb();
+	isb();
 }
 
 static void etm_clr_pwrup(struct etm_drvdata *drvdata)
 {
 	uint32_t etmpdcr;
 
-	etmpdcr = etm_readl(drvdata, ETMPDCR);
+	/* ensure pending cp14 accesses complete before clearing pwrup */
+	mb();
+	isb();
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
 	etmpdcr &= ~BIT(3);
-	etm_writel(drvdata, etmpdcr, ETMPDCR);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
 }
 
 static void etm_set_prog(struct etm_drvdata *drvdata)
@@ -240,6 +309,10 @@
 	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr |= BIT(10);
 	etm_writel(drvdata, etmcr, ETMCR);
+	/* recommended by spec for cp14 accesses to ensure etmcr write is
+	 * complete before polling etmsr
+	 */
+	isb();
 	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 1
 				&& count > 0; count--)
 		udelay(1);
@@ -255,6 +328,10 @@
 	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr &= ~BIT(10);
 	etm_writel(drvdata, etmcr, ETMCR);
+	/* recommended by spec for cp14 accesses to ensure etmcr write is
+	 * complete before polling etmsr
+	 */
+	isb();
 	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 0
 				&& count > 0; count--)
 		udelay(1);
@@ -262,17 +339,94 @@
 	     etm_readl(drvdata, ETMSR));
 }
 
-static void __etm_enable(void *info)
+static void etm_save_pwrdwn(struct etm_drvdata *drvdata)
 {
-	int i;
+	drvdata->ctrl_pwrdwn = BVAL(etm_readl(drvdata, ETMCR), 0);
+}
+
+static void etm_restore_pwrdwn(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr = (etmcr & ~BIT(0)) | drvdata->ctrl_pwrdwn;
+	etm_writel(drvdata, etmcr, ETMCR);
+}
+
+static void etm_save_pwrup(struct etm_drvdata *drvdata)
+{
+	drvdata->pdcr_pwrup = BVAL(etm_readl_mm(drvdata, ETMPDCR), 3);
+}
+
+static void etm_restore_pwrup(struct etm_drvdata *drvdata)
+{
+	uint32_t etmpdcr;
+
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+	etmpdcr = (etmpdcr & ~BIT(3)) | (drvdata->pdcr_pwrup << 3);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+}
+
+static void etm_enable_pcsave(void *info)
+{
 	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
-	/* Vote for ETM power/clock enable */
+
+	etm_save_pwrup(drvdata);
+	/*
+	 * ETMPDCR is only accessible via memory mapped interface and so use
+	 * it first to enable power/clock to allow subsequent cp14 accesses.
+	 */
 	etm_set_pwrup(drvdata);
+	etm_clr_pwrdwn(drvdata);
+	etm_restore_pwrup(drvdata);
+
+	ETM_LOCK(drvdata);
+}
+
+static void etm_disable_pcsave(void *info)
+{
+	struct etm_drvdata *drvdata = info;
+
+	ETM_UNLOCK(drvdata);
+
+	etm_save_pwrup(drvdata);
+	/*
+	 * ETMPDCR is only accessible via memory mapped interface and so use
+	 * it first to enable power/clock to allow subsequent cp14 accesses.
+	 */
+	etm_set_pwrup(drvdata);
+	etm_set_pwrdwn(drvdata);
+	etm_restore_pwrup(drvdata);
+
+	ETM_LOCK(drvdata);
+}
+
+static void __etm_enable(void *info)
+{
+	int i;
+	uint32_t etmcr;
+	struct etm_drvdata *drvdata = info;
+
+	ETM_UNLOCK(drvdata);
+	/*
+	 * Vote for ETM power/clock enable. ETMPDCR is only accessible via
+	 * memory mapped interface and so use it first to enable power/clock
+	 * to allow subsequent cp14 accesses.
+	 */
+	etm_set_pwrup(drvdata);
+	etm_save_pwrdwn(drvdata);
+	/*
+	 * Clear power down bit since when this bit is set writes to
+	 * certain registers might be ignored.
+	 */
+	etm_clr_pwrdwn(drvdata);
 	etm_set_prog(drvdata);
 
-	etm_writel(drvdata, drvdata->ctrl | BIT(10), ETMCR);
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr &= (BIT(10) | BIT(0));
+	etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
 	etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
 	etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
 	etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
@@ -309,6 +463,7 @@
 	etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
 
 	etm_clr_prog(drvdata);
+	etm_restore_pwrdwn(drvdata);
 	ETM_LOCK(drvdata);
 
 	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
@@ -346,11 +501,18 @@
 	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
+	etm_save_pwrdwn(drvdata);
+	/*
+	 * Clear power down bit since when this bit is set writes to
+	 * certain registers might be ignored.
+	 */
+	etm_clr_pwrdwn(drvdata);
 	etm_set_prog(drvdata);
 
 	/* program trace enable to low by using always false event */
 	etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
 
+	etm_restore_pwrdwn(drvdata);
 	/* Vote for ETM power/clock disable */
 	etm_clr_pwrup(drvdata);
 	ETM_LOCK(drvdata);
@@ -1307,6 +1469,7 @@
 {
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->sync_freq;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1352,6 +1515,60 @@
 static DEVICE_ATTR(timestamp_event, S_IRUGO | S_IWUSR, etm_show_timestamp_event,
 		   etm_store_timestamp_event);
 
+static ssize_t etm_show_pcsave(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	val = drvdata->pcsave_enable;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
+{
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	mutex_lock(&drvdata->mutex);
+	if (val) {
+		smp_call_function_single(drvdata->cpu, etm_enable_pcsave,
+					 drvdata, 1);
+		drvdata->pcsave_enable = true;
+	} else {
+		smp_call_function_single(drvdata->cpu, etm_disable_pcsave,
+					 drvdata, 1);
+		drvdata->pcsave_enable = false;
+	}
+	mutex_unlock(&drvdata->mutex);
+
+	clk_disable_unprepare(drvdata->clk);
+	return 0;
+}
+
+static ssize_t etm_store_pcsave(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	int ret;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	ret = __etm_store_pcsave(drvdata, val);
+	if (ret)
+		return ret;
+
+	return size;
+}
+static DEVICE_ATTR(pcsave, S_IRUGO | S_IWUSR, etm_show_pcsave,
+		   etm_store_pcsave);
+
 static struct attribute *etm_attrs[] = {
 	&dev_attr_nr_addr_cmp.attr,
 	&dev_attr_nr_cntr.attr,
@@ -1416,17 +1633,33 @@
 	return true;
 }
 
-static void __devinit etm_init_arch_data(struct etm_drvdata *drvdata)
+static void __devinit etm_prepare_arch(struct etm_drvdata *drvdata)
+{
+	/* Unlock OS lock first to allow memory mapped reads and writes. This
+	 * is required for Krait pass1
+	 * */
+	etm_os_unlock(NULL);
+	smp_call_function(etm_os_unlock, NULL, 1);
+}
+
+static void __devinit etm_init_arch_data(void *info)
 {
 	uint32_t etmidr;
 	uint32_t etmccr;
+	struct etm_drvdata *drvdata = info;
 
-	/* Unlock OS lock first to allow memory mapped reads and writes */
-	etm_os_unlock(NULL);
-	smp_call_function(etm_os_unlock, NULL, 1);
 	ETM_UNLOCK(drvdata);
-	/* Vote for ETM power/clock enable */
+	/*
+	 * Vote for ETM power/clock enable. ETMPDCR is only accessible via
+	 * memory mapped interface and so use it first to enable power/clock
+	 * to allow subsequent cp14 accesses.
+	 */
 	etm_set_pwrup(drvdata);
+	/*
+	 * Clear power down bit since when this bit is set writes to
+	 * certain registers might be ignored.
+	 */
+	etm_clr_pwrdwn(drvdata);
 	/* Set prog bit. It will be set from reset but this is included to
 	 * ensure it is set
 	 */
@@ -1443,6 +1676,7 @@
 	drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
 	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
+	etm_set_pwrdwn(drvdata);
 	/* Vote for ETM power/clock disable */
 	etm_clr_pwrup(drvdata);
 	ETM_LOCK(drvdata);
@@ -1518,12 +1752,6 @@
 	struct msm_client_dump dump;
 	struct coresight_desc *desc;
 
-	/* Fail probe for Krait pass3 until supported */
-	if (cpu_is_krait_v3()) {
-		dev_info(dev, "ETM: failing probe for Krait pass3\n");
-		return -EINVAL;
-	}
-
 	if (pdev->dev.of_node) {
 		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
 		if (IS_ERR(pdata))
@@ -1569,7 +1797,9 @@
 	 * ETMs copy it over from ETM0.
 	 */
 	if (drvdata->cpu == 0) {
-		etm_init_arch_data(drvdata);
+		etm_prepare_arch(drvdata);
+		smp_call_function_single(drvdata->cpu, etm_init_arch_data,
+					 drvdata, 1);
 		etm0drvdata = drvdata;
 	} else {
 		etm_copy_arch_data(drvdata);
@@ -1615,11 +1845,24 @@
 		goto err0;
 	}
 
+	if (pdev->dev.of_node)
+		drvdata->pcsave_impl = of_property_read_bool(pdev->dev.of_node,
+							     "qcom,pc-save");
+	if (drvdata->pcsave_impl) {
+		ret = device_create_file(&drvdata->csdev->dev,
+					 &dev_attr_pcsave);
+		if (ret)
+			dev_err(dev, "ETM pcsave dev node creation failed\n");
+	}
+
 	dev_info(dev, "ETM initialized\n");
 
 	if (boot_enable)
 		coresight_enable(drvdata->csdev);
 
+	if (drvdata->pcsave_impl && boot_pcsave_enable)
+		__etm_store_pcsave(drvdata, true);
+
 	return 0;
 err1:
 	clk_disable_unprepare(drvdata->clk);
@@ -1633,6 +1876,7 @@
 {
 	struct etm_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	device_remove_file(&drvdata->csdev->dev, &dev_attr_pcsave);
 	coresight_unregister(drvdata->csdev);
 	wake_lock_destroy(&drvdata->wake_lock);
 	mutex_destroy(&drvdata->mutex);
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 2b00242..0cf2b3d 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -39,9 +39,13 @@
 #ifdef CONFIG_MSM_QDSS
 extern void msm_qdss_csr_enable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_bam_to_usb(void);
+extern unsigned int etm_readl_cp14(uint32_t off);
+extern void etm_writel_cp14(uint32_t val, uint32_t off);
 #else
 static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
+static inline unsigned int etm_readl_cp14(uint32_t off) { return 0; }
+static inline void etm_writel_cp14(uint32_t val, uint32_t off) {}
 #endif
 
 #endif
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 70b2c43..f6a948b 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -724,6 +724,13 @@
 
 	dev_info(drvdata->dev, "STM initialized\n");
 
+	/*
+	 * Enable and disable STM to undo the temporary default STM enable
+	 * done by RPM.
+	 */
+	coresight_enable(drvdata->csdev);
+	coresight_disable(drvdata->csdev);
+
 	if (boot_enable)
 		coresight_enable(drvdata->csdev);
 
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0be5882..13f69cd 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1060,6 +1060,7 @@
 			goto err0;
 		}
 		memset(drvdata->vaddr, 0, drvdata->size);
+		drvdata->buf = drvdata->vaddr;
 		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
 
 		ret = tmc_etr_bam_init(pdev, drvdata);
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index cccb5a7..3974f2e 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -377,8 +377,10 @@
 
 	list_for_each_entry(cd, &coresight_devs, dev_link) {
 		if (cd->id == curr_sink) {
-			if (cd->enable && cd->ops->sink_ops->abort)
+			if (cd->enable && cd->ops->sink_ops->abort) {
 				cd->ops->sink_ops->abort(cd);
+				cd->enable = false;
+			}
 		}
 	}
 out:
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 9c49f80..4eeff35 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -138,7 +138,6 @@
 {
 	int ret = 0;
 	int cpu;
-	uint32_t group_id = 0x43505530; /* CPU0 */
 	struct msm_dcvs_core_info *core = NULL;
 
 	core = pdev->dev.platform_data;
@@ -146,7 +145,7 @@
 	for_each_possible_cpu(cpu) {
 		mutex_init(&per_cpu(gov_mutex, cpu));
 		snprintf(core_name[cpu], 10, "cpu%d", cpu);
-		ret = msm_dcvs_register_core(core_name[cpu], group_id, core);
+		ret = msm_dcvs_register_core(core_name[cpu], core);
 		if (ret)
 			pr_err("Unable to register core for %d\n", cpu);
 	}
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index b23181f..a48e6b2 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -430,7 +430,8 @@
 		if (!((1 << heap->id) & heap_mask))
 			continue;
 		/* Do not allow un-secure heap if secure is specified */
-		if (secure_allocation && (heap->type != ION_HEAP_TYPE_CP))
+		if (secure_allocation &&
+			(heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP))
 			continue;
 		buffer = ion_buffer_create(heap, dev, len, align, flags);
 		if (!IS_ERR_OR_NULL(buffer))
@@ -865,7 +866,7 @@
 
 		if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
 			type == ION_HEAP_TYPE_CARVEOUT ||
-			type == ION_HEAP_TYPE_CP)
+			type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
 			seq_printf(s, " : %12lx", handle->buffer->priv_phys);
 		else
 			seq_printf(s, " : %12s", "N/A");
@@ -1656,7 +1657,7 @@
 	mutex_lock(&dev->lock);
 	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
 		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
-		if (heap->type != ION_HEAP_TYPE_CP)
+		if (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP)
 			continue;
 		if (ION_HEAP(heap->id) != heap_id)
 			continue;
@@ -1684,7 +1685,7 @@
 	mutex_lock(&dev->lock);
 	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
 		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
-		if (heap->type != ION_HEAP_TYPE_CP)
+		if (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP)
 			continue;
 		if (ION_HEAP(heap->id) != heap_id)
 			continue;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 9f33859..2070abf 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -930,7 +930,7 @@
 	cp_heap->kmap_uncached_count = 0;
 	cp_heap->total_size = heap_data->size;
 	cp_heap->heap.ops = &cp_heap_ops;
-	cp_heap->heap.type = ION_HEAP_TYPE_CP;
+	cp_heap->heap.type = (enum ion_heap_type) ION_HEAP_TYPE_CP;
 	cp_heap->heap_protected = HEAP_NOT_PROTECTED;
 	cp_heap->secure_base = cp_heap->base;
 	cp_heap->secure_size = heap_data->size;
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 165a7bf..4c83d75 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -24,7 +24,7 @@
 {
 	struct ion_heap *heap = NULL;
 
-	switch (heap_data->type) {
+	switch ((int) heap_data->type) {
 	case ION_HEAP_TYPE_SYSTEM_CONTIG:
 		heap = ion_system_contig_heap_create(heap_data);
 		break;
@@ -63,7 +63,7 @@
 	if (!heap)
 		return;
 
-	switch (heap->type) {
+	switch ((int) heap->type) {
 	case ION_HEAP_TYPE_SYSTEM_CONTIG:
 		ion_system_contig_heap_destroy(heap);
 		break;
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 4c9be1d..deff514 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -264,7 +264,7 @@
 
 	if (!heap->base && heap->extra_data) {
 		unsigned int align = 0;
-		switch (heap->type) {
+		switch ((int) heap->type) {
 		case ION_HEAP_TYPE_CARVEOUT:
 			align =
 			((struct ion_co_heap_pdata *) heap->extra_data)->align;
@@ -346,7 +346,7 @@
 {
 	int ret = 0;
 
-	switch (heap->type) {
+	switch ((int) heap->type) {
 	case ION_HEAP_TYPE_CP:
 	{
 		heap->extra_data = kzalloc(sizeof(struct ion_cp_heap_pdata),
@@ -414,7 +414,7 @@
 
 	int ret = of_property_read_u32(node, "qcom,heap-align", &val);
 	if (!ret) {
-		switch (heap->type) {
+		switch ((int) heap->type) {
 		case ION_HEAP_TYPE_CP:
 		{
 			struct ion_cp_heap_pdata *extra =
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 05c7967..6a010a9 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -65,13 +65,17 @@
 #define A3XX_RBBM_INT_CLEAR_CMD 0x061
 #define A3XX_RBBM_INT_0_MASK 0x063
 #define A3XX_RBBM_INT_0_STATUS 0x064
+#define A3XX_RBBM_PERFCTR_CTL 0x80
 #define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
+#define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
 #define A3XX_RBBM_RBBM_CTL 0x100
 #define A3XX_RBBM_RBBM_CTL 0x100
 #define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
 #define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
 #define A3XX_RBBM_DEBUG_BUS_CTL             0x111
 #define A3XX_RBBM_DEBUG_BUS_DATA_STATUS     0x112
+
 /* Following two are same as on A2XX, just in a different place */
 #define A3XX_CP_PFP_UCODE_ADDR 0x1C9
 #define A3XX_CP_PFP_UCODE_DATA 0x1CA
@@ -160,6 +164,7 @@
 #define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
 #define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
 #define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
@@ -528,4 +533,7 @@
 /* RBBM_CLOCK_CTL default value */
 #define A3XX_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
 
+/* COUNTABLE FOR SP PERFCOUNTER */
+#define SP_FS_FULL_ALU_INSTRUCTIONS    0x0E
+
 #endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index cf7f3ce..573e0a6 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -127,6 +127,8 @@
 	REG_CP_IB1_BUFSZ,
 	REG_CP_IB2_BASE,
 	REG_CP_IB2_BUFSZ,
+	0,
+	0
 };
 
 const unsigned int hang_detect_regs_count = ARRAY_SIZE(hang_detect_regs);
@@ -847,15 +849,15 @@
 	for_each_child_of_node(node, child)
 		count++;
 
-	info->core_param.num_freq = count;
+	info->power_param.num_freq = count;
 
-	info->freq_tbl = kzalloc(info->core_param.num_freq *
+	info->freq_tbl = kzalloc(info->power_param.num_freq *
 			sizeof(struct msm_dcvs_freq_entry),
 			GFP_KERNEL);
 
 	if (info->freq_tbl == NULL) {
 		KGSL_CORE_ERR("kzalloc(%d) failed\n",
-			info->core_param.num_freq *
+			info->power_param.num_freq *
 			sizeof(struct msm_dcvs_freq_entry));
 		ret = -ENOMEM;
 		goto err;
@@ -867,7 +869,7 @@
 		if (adreno_of_read_property(child, "reg", &index))
 			goto err;
 
-		if (index >= info->core_param.num_freq) {
+		if (index >= info->power_param.num_freq) {
 			KGSL_CORE_ERR("DCVS freq entry %d is out of range\n",
 				index);
 			continue;
@@ -877,43 +879,96 @@
 			&info->freq_tbl[index].freq))
 			goto err;
 
-		if (adreno_of_read_property(child, "qcom,idle-energy",
-			&info->freq_tbl[index].idle_energy))
-			info->freq_tbl[index].idle_energy = 0;
+		if (adreno_of_read_property(child, "qcom,voltage",
+			&info->freq_tbl[index].voltage))
+			info->freq_tbl[index].voltage = 0;
 
-		if (adreno_of_read_property(child, "qcom,active-energy",
-			&info->freq_tbl[index].active_energy))
-			info->freq_tbl[index].active_energy = 0;
+		if (adreno_of_read_property(child, "qcom,is_trans_level",
+			&info->freq_tbl[index].is_trans_level))
+			info->freq_tbl[index].is_trans_level = 0;
+
+		if (adreno_of_read_property(child, "qcom,active-energy-offset",
+			&info->freq_tbl[index].active_energy_offset))
+			info->freq_tbl[index].active_energy_offset = 0;
+
+		if (adreno_of_read_property(child, "qcom,leakage-energy-offset",
+			&info->freq_tbl[index].leakage_energy_offset))
+			info->freq_tbl[index].leakage_energy_offset = 0;
 	}
 
-	if (adreno_of_read_property(node, "qcom,core-max-time-us",
-		&info->core_param.max_time_us))
-		goto err;
-
-	if (adreno_of_read_property(node, "qcom,algo-slack-time-us",
-		&info->algo_param.slack_time_us))
+	if (adreno_of_read_property(node, "qcom,core-core-type",
+		&info->core_param.core_type))
 		goto err;
 
 	if (adreno_of_read_property(node, "qcom,algo-disable-pc-threshold",
 		&info->algo_param.disable_pc_threshold))
 		goto err;
-
-	if (adreno_of_read_property(node, "qcom,algo-ss-window-size",
-		&info->algo_param.ss_window_size))
+	if (adreno_of_read_property(node, "qcom,algo-em-win-size-min-us",
+		&info->algo_param.em_win_size_min_us))
 		goto err;
-
-	if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
-		&info->algo_param.ss_util_pct))
+	if (adreno_of_read_property(node, "qcom,algo-em-win-size-max-us",
+		&info->algo_param.em_win_size_max_us))
 		goto err;
-
 	if (adreno_of_read_property(node, "qcom,algo-em-max-util-pct",
 		&info->algo_param.em_max_util_pct))
 		goto err;
-
+	if (adreno_of_read_property(node, "qcom,algo-group-id",
+		&info->algo_param.group_id))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-max-freq-chg-time-us",
+		&info->algo_param.max_freq_chg_time_us))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-slack-mode-dynamic",
+		&info->algo_param.slack_mode_dynamic))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-slack-weight-thresh-pct",
+		&info->algo_param.slack_weight_thresh_pct))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-slack-time-min-us",
+		&info->algo_param.slack_time_min_us))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-slack-time-max-us",
+		&info->algo_param.slack_time_max_us))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-ss-win-size-min-us",
+		&info->algo_param.ss_win_size_min_us))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-ss-win-size-max-us",
+		&info->algo_param.ss_win_size_max_us))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
+		&info->algo_param.ss_util_pct))
+		goto err;
 	if (adreno_of_read_property(node, "qcom,algo-ss-iobusy-conv",
 		&info->algo_param.ss_iobusy_conv))
 		goto err;
 
+	if (adreno_of_read_property(node, "qcom,energy-active-coeff-a",
+		&info->energy_coeffs.active_coeff_a))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,energy-active-coeff-b",
+		&info->energy_coeffs.active_coeff_b))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,energy-active-coeff-c",
+		&info->energy_coeffs.active_coeff_c))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-a",
+		&info->energy_coeffs.leakage_coeff_a))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-b",
+		&info->energy_coeffs.leakage_coeff_b))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-c",
+		&info->energy_coeffs.leakage_coeff_c))
+		goto err;
+	if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-d",
+		&info->energy_coeffs.leakage_coeff_d))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,power-current-temp",
+		&info->power_param.current_temp))
+		goto err;
+
 	return info;
 
 err:
@@ -1233,6 +1288,12 @@
 	 */
 	hang_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
 
+	/* Add A3XX specific registers for hang detection */
+	if (adreno_is_a3xx(adreno_dev)) {
+		hang_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
+		hang_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
+	}
+
 	status = kgsl_mmu_start(device);
 	if (status)
 		goto error_clk_off;
@@ -2155,7 +2216,14 @@
 	if (!adreno_dev->fast_hang_detect)
 		return 0;
 
+	if (device->ftbl->isidle(device))
+		return 0;
+
 	for (i = 0; i < hang_detect_regs_count; i++) {
+
+		if (hang_detect_regs[i] == 0)
+			continue;
+
 		adreno_regread(device, hang_detect_regs[i],
 					   &curr_reg_val[i]);
 		if (curr_reg_val[i] != prev_reg_val[i]) {
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 2388fff..8de2c70 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1749,9 +1749,6 @@
 	if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
 		queue_work(device->work_queue, &device->ts_expired_ws);
 		wake_up_interruptible_all(&device->wait_queue);
-		atomic_notifier_call_chain(&(device->ts_notifier_list),
-					   device->id,
-					   NULL);
 	}
 }
 
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 7bf928f..104baf8 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2587,9 +2587,6 @@
 
 	/* Schedule work to free mem and issue ibs */
 	queue_work(device->work_queue, &device->ts_expired_ws);
-
-	atomic_notifier_call_chain(&device->ts_notifier_list,
-				   device->id, NULL);
 }
 
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
@@ -2836,6 +2833,17 @@
 		adreno_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
 			(unsigned int)(adreno_dev->ocmem_base >> 14));
 	}
+
+	/* Turn on performance counters */
+	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
+
+	/*
+	 * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS
+	 * we will use this to augment our hang detection
+	 */
+
+	adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
+		SP_FS_FULL_ALU_INSTRUCTIONS);
 }
 
 /* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1ff219b..0dd140b 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -503,7 +503,7 @@
 	 * support, we must use the global timestamp since issueibcmds
 	 * will be returning that one.
 	 */
-	if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
 		context_id = context->id;
 
 	/* reserve space to temporarily turn off protected mode
@@ -518,7 +518,7 @@
 		total_sizedwords += 7;
 
 	total_sizedwords += 2; /* scratchpad ts for recovery */
-	if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
+	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
 		total_sizedwords += 3; /* sop timestamp */
 		total_sizedwords += 4; /* eop timestamp */
 		total_sizedwords += 3; /* global timestamp without cache
@@ -591,7 +591,7 @@
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
 	}
 
-	if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
+	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
 		/* start-of-pipeline timestamp */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
@@ -902,6 +902,7 @@
 	unsigned int i;
 	struct adreno_context *drawctxt;
 	unsigned int start_index = 0;
+	int ret;
 
 	if (device->state & KGSL_STATE_HUNG)
 		return -EBUSY;
@@ -948,9 +949,15 @@
 		if (unlikely(adreno_dev->ib_check_level >= 1 &&
 		    !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
 				ibdesc[i].sizedwords))) {
-			kfree(link);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto done;
 		}
+
+		if (ibdesc[i].sizedwords == 0) {
+			ret = -EINVAL;
+			goto done;
+		}
+
 		*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
 		*cmds++ = ibdesc[i].gpuaddr;
 		*cmds++ = ibdesc[i].sizedwords;
@@ -972,7 +979,6 @@
 	KGSL_CMD_INFO(device, "<%d:0x%x> g %08x numibs %d\n",
 		context->id, *timestamp, (unsigned int)ibdesc, numibs);
 
-	kfree(link);
 
 #ifdef CONFIG_MSM_KGSL_CFF_DUMP
 	/*
@@ -982,13 +988,16 @@
 	 */
 	adreno_idle(device);
 #endif
+
 	/* If context hung and recovered then return error so that the
 	 * application may handle it */
-	if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED)
-		return -EDEADLK;
-	else
-		return 0;
 
+	ret = (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED) ?
+		-EDEADLK : 0;
+
+done:
+	kfree(link);
+	return ret;
 }
 
 static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5904abb..5ba844a 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -357,7 +357,7 @@
 
 	/* MAX - 1, there is one memdesc in memstore for device info */
 	if (id >= KGSL_MEMSTORE_MAX) {
-		KGSL_DRV_ERR(dev_priv->device, "cannot have more than %d "
+		KGSL_DRV_INFO(dev_priv->device, "cannot have more than %d "
 				"ctxts due to memstore limitation\n",
 				KGSL_MEMSTORE_MAX);
 		idr_remove(&dev_priv->device->context_idr, id);
@@ -507,24 +507,6 @@
 	return ret;
 }
 
-int kgsl_register_ts_notifier(struct kgsl_device *device,
-			      struct notifier_block *nb)
-{
-	BUG_ON(device == NULL);
-	return atomic_notifier_chain_register(&device->ts_notifier_list,
-					      nb);
-}
-EXPORT_SYMBOL(kgsl_register_ts_notifier);
-
-int kgsl_unregister_ts_notifier(struct kgsl_device *device,
-				struct notifier_block *nb)
-{
-	BUG_ON(device == NULL);
-	return atomic_notifier_chain_unregister(&device->ts_notifier_list,
-						nb);
-}
-EXPORT_SYMBOL(kgsl_unregister_ts_notifier);
-
 int kgsl_check_timestamp(struct kgsl_device *device,
 	struct kgsl_context *context, unsigned int timestamp)
 {
@@ -1080,11 +1062,8 @@
 	int result;
 
 	context = kgsl_find_context(dev_priv, param->context_id);
-	if (context == NULL) {
-		KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
-			param->context_id);
+	if (context == NULL)
 		return -EINVAL;
-	}
 	/*
 	 * A reference count is needed here, because waittimestamp may
 	 * block with the device mutex unlocked and userspace could
@@ -1108,17 +1087,11 @@
 	context = kgsl_find_context(dev_priv, param->drawctxt_id);
 	if (context == NULL) {
 		result = -EINVAL;
-		KGSL_DRV_ERR(dev_priv->device,
-			"invalid context_id %d\n",
-			param->drawctxt_id);
 		goto done;
 	}
 
 	if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
 		if (!param->numibs) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"Invalid numibs as parameter: %d\n",
-				 param->numibs);
 			result = -EINVAL;
 			goto done;
 		}
@@ -1129,9 +1102,6 @@
 		 */
 
 		if (param->numibs > 10000) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"Too many IBs submitted. count: %d max 10000\n",
-				param->numibs);
 			result = -EINVAL;
 			goto done;
 		}
@@ -1218,11 +1188,8 @@
 	struct kgsl_context *context;
 
 	context = kgsl_find_context(dev_priv, param->context_id);
-	if (context == NULL) {
-		KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
-			param->context_id);
+	if (context == NULL)
 		return -EINVAL;
-	}
 
 	return _cmdstream_readtimestamp(dev_priv, context,
 			param->type, &param->timestamp);
@@ -1287,11 +1254,8 @@
 	struct kgsl_context *context;
 
 	context = kgsl_find_context(dev_priv, param->context_id);
-	if (context == NULL) {
-		KGSL_DRV_ERR(dev_priv->device,
-			"invalid drawctxt context_id %d\n", param->context_id);
+	if (context == NULL)
 		return -EINVAL;
-	}
 
 	return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
 			context, param->timestamp, param->type);
@@ -1788,6 +1752,8 @@
 	if (result)
 		goto error;
 
+	entry->memdesc.priv |= param->flags & KGSL_MEMTYPE_MASK;
+
 	result = kgsl_mmu_map(private->pagetable,
 			      &entry->memdesc,
 			      GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2ca3a4f..dc597f5 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -155,7 +155,6 @@
 	struct kgsl_pwrctrl pwrctrl;
 	int open_count;
 
-	struct atomic_notifier_head ts_notifier_list;
 	struct mutex mutex;
 	uint32_t state;
 	uint32_t requested_state;
@@ -210,7 +209,6 @@
 	.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
 	.suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
 	.recovery_gate = COMPLETION_INITIALIZER((_dev).recovery_gate),\
-	.ts_notifier_list = ATOMIC_NOTIFIER_INIT((_dev).ts_notifier_list),\
 	.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
 			kgsl_idle_check),\
 	.ts_expired_ws  = __WORK_INITIALIZER((_dev).ts_expired_ws,\
@@ -374,12 +372,6 @@
 int kgsl_check_timestamp(struct kgsl_device *device,
 		struct kgsl_context *context, unsigned int timestamp);
 
-int kgsl_register_ts_notifier(struct kgsl_device *device,
-			      struct notifier_block *nb);
-
-int kgsl_unregister_ts_notifier(struct kgsl_device *device,
-				struct notifier_block *nb);
-
 int kgsl_device_platform_probe(struct kgsl_device *device);
 
 void kgsl_device_platform_remove(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 0e1e100..54ba5ad 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -729,7 +729,8 @@
 		return 0;
 
 	gpuaddr = memdesc->gpuaddr;
-	memdesc->priv |= KGSL_MEMFLAGS_GLOBAL;
+	memdesc->priv |= KGSL_MEMFLAGS_GLOBAL
+			| (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
 
 	result = kgsl_mmu_map(pagetable, memdesc, protflags);
 	if (result)
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index 879b381..acf22ac 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -170,9 +170,8 @@
 	/* Fill in frequency table from low to high, reversing order. */
 	low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
 	for (i = 0; i <= low_level; i++)
-		tbl[i].freq =
-			pwr->pwrlevels[low_level - i].gpu_freq / 1000;
-	ret = msm_dcvs_register_core(device->name, 0, priv->core_info);
+		tbl[i].freq = pwr->pwrlevels[low_level - i].gpu_freq / 1000;
+	ret = msm_dcvs_register_core(device->name, priv->core_info);
 	if (ret) {
 		KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
 		goto err;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index c2ce5c7..bdc5686 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -540,7 +540,6 @@
 
 	memdesc->size = size;
 	memdesc->pagetable = pagetable;
-	memdesc->priv = KGSL_MEMFLAGS_CACHED;
 	memdesc->ops = &kgsl_page_alloc_ops;
 
 	memdesc->sg = kgsl_sg_alloc(sglen);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index de89ac1..5a6c4c2 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -27,8 +27,6 @@
 #define KGSL_CACHE_OP_FLUSH     0x02
 #define KGSL_CACHE_OP_CLEAN     0x03
 
-/** Set if the memdesc describes cached memory */
-#define KGSL_MEMFLAGS_CACHED    0x00000001
 /** Set if the memdesc is mapped into all pagetables */
 #define KGSL_MEMFLAGS_GLOBAL    0x00000002
 
@@ -136,6 +134,7 @@
 {
 	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
 		return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
+	memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
 	return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
 }
 
@@ -144,10 +143,17 @@
 		struct kgsl_pagetable *pagetable,
 		size_t size, unsigned int flags)
 {
+	int ret;
+	unsigned int mask = (KGSL_MEMTYPE_MASK | KGSL_MEMFLAGS_GPUREADONLY);
 	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
-		return kgsl_sharedmem_ebimem_user(memdesc, pagetable, size,
+		ret = kgsl_sharedmem_ebimem_user(memdesc, pagetable, size,
 						  flags);
-	return kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size, flags);
+	else
+		ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size,
+							flags);
+	if (ret == 0)
+		memdesc->priv |= flags & mask;
+	return ret;
 }
 
 static inline int
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 81ab3fb..bba06bc 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -315,16 +315,18 @@
 	TP_STRUCT__entry(
 		__field(unsigned int, gpuaddr)
 		__field(unsigned int, size)
+		__field(unsigned int, tgid)
 	),
 
 	TP_fast_assign(
 		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
 		__entry->size = mem_entry->memdesc.size;
+		__entry->tgid = mem_entry->priv->pid;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d",
-		__entry->gpuaddr, __entry->size
+		"gpuaddr=0x%08x size=%d tgid=%d",
+		__entry->gpuaddr, __entry->size, __entry->tgid
 	)
 );
 
@@ -339,6 +341,7 @@
 		__field(unsigned int, size)
 		__field(int, fd)
 		__field(int, type)
+		__field(unsigned int, tgid)
 	),
 
 	TP_fast_assign(
@@ -346,12 +349,13 @@
 		__entry->size = mem_entry->memdesc.size;
 		__entry->fd = fd;
 		__entry->type = mem_entry->memtype;
+		__entry->tgid = mem_entry->priv->pid;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d type=%d fd=%d",
+		"gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d",
 		__entry->gpuaddr, __entry->size,
-		__entry->type, __entry->fd
+		__entry->type, __entry->fd, __entry->tgid
 	)
 );
 
@@ -366,17 +370,20 @@
 		__field(unsigned int, size)
 		__field(int, type)
 		__field(int, fd)
+		__field(unsigned int, tgid)
 	),
 
 	TP_fast_assign(
 		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
 		__entry->size = mem_entry->memdesc.size;
 		__entry->type = mem_entry->memtype;
+		__entry->tgid = mem_entry->priv->pid;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d type=%d",
-		__entry->gpuaddr, __entry->size, __entry->type
+		"gpuaddr=0x%08x size=%d type=%d tgid=%d",
+		__entry->gpuaddr, __entry->size, __entry->type,
+		__entry->tgid
 	)
 );
 
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 8ddc991..712bc60 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -212,10 +212,6 @@
 
 			queue_work(device->work_queue, &device->ts_expired_ws);
 			wake_up_interruptible(&device->wait_queue);
-
-			atomic_notifier_call_chain(
-				&(device->ts_notifier_list),
-				device->id, NULL);
 		}
 	}
 
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 9f64cec..abd66f4 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -104,14 +104,75 @@
 static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
 		pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
 
+static int pmic8xxx_set_pon1(struct device *dev, u32 debounce_us, bool pull_up)
+{
+	int err;
+	u32 delay;
+	u8 pon_cntl;
+
+	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+	if (debounce_us > USEC_PER_SEC * 2 ||
+		debounce_us < USEC_PER_SEC / 64) {
+		dev_err(dev, "invalid power key trigger delay\n");
+		return -EINVAL;
+	}
+
+	delay = (debounce_us << 6) / USEC_PER_SEC;
+	delay = ilog2(delay);
+
+	err = pm8xxx_readb(dev->parent, PON_CNTL_1, &pon_cntl);
+	if (err < 0) {
+		dev_err(dev, "failed reading PON_CNTL_1 err=%d\n", err);
+		return err;
+	}
+
+	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+
+	if (pull_up)
+		pon_cntl |= PON_CNTL_PULL_UP;
+	else
+		pon_cntl &= ~PON_CNTL_PULL_UP;
+
+	err = pm8xxx_writeb(dev->parent, PON_CNTL_1, pon_cntl);
+	if (err < 0) {
+		dev_err(dev, "failed writing PON_CNTL_1 err=%d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static ssize_t pmic8xxx_debounce_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t size)
+{
+	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+	int err;
+	unsigned long val;
+
+	if (size > 8)
+		return -EINVAL;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	err = pmic8xxx_set_pon1(dev, val, pwrkey->pdata->pull_up);
+	if (err < 0)
+		return err;
+
+	return size;
+}
+
+static DEVICE_ATTR(debounce_us, 0664, NULL, pmic8xxx_debounce_store);
+
 static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
 {
 	struct input_dev *pwr;
 	int key_release_irq = platform_get_irq(pdev, 0);
 	int key_press_irq = platform_get_irq(pdev, 1);
 	int err;
-	unsigned int delay;
-	u8 pon_cntl;
 	struct pmic8xxx_pwrkey *pwrkey;
 	const struct pm8xxx_pwrkey_platform_data *pdata =
 					dev_get_platdata(&pdev->dev);
@@ -121,13 +182,6 @@
 		return -EINVAL;
 	}
 
-	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
-	if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
-		pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
-		dev_err(&pdev->dev, "invalid power key trigger delay\n");
-		return -EINVAL;
-	}
-
 	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
 	if (!pwrkey)
 		return -ENOMEM;
@@ -147,25 +201,10 @@
 	pwr->phys = "pmic8xxx_pwrkey/input0";
 	pwr->dev.parent = &pdev->dev;
 
-	delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
-	delay = ilog2(delay);
-
-	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
-		goto free_input_dev;
-	}
-
-	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
-	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
-	if (pdata->pull_up)
-		pon_cntl |= PON_CNTL_PULL_UP;
-	else
-		pon_cntl &= ~PON_CNTL_PULL_UP;
-
-	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+	err = pmic8xxx_set_pon1(&pdev->dev,
+			pdata->kpd_trigger_delay_us, pdata->pull_up);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't set PON CTRL1 register: %d\n", err);
 		goto free_input_dev;
 	}
 
@@ -178,10 +217,22 @@
 	pwrkey->key_press_irq = key_press_irq;
 	pwrkey->key_release_irq = key_release_irq;
 	pwrkey->pwr = pwr;
-	pwrkey->press = false;
 
 	platform_set_drvdata(pdev, pwrkey);
 
+	/* check power key status during boot */
+	err = pm8xxx_read_irq_stat(pdev->dev.parent, key_press_irq);
+	if (err < 0) {
+		dev_err(&pdev->dev, "reading irq status failed\n");
+		goto unreg_input_dev;
+	}
+	pwrkey->press = !!err;
+
+	if (pwrkey->press) {
+		input_report_key(pwrkey->pwr, KEY_POWER, 1);
+		input_sync(pwrkey->pwr);
+	}
+
 	err = request_any_context_irq(key_press_irq, pwrkey_press_irq,
 		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
 	if (err < 0) {
@@ -199,12 +250,22 @@
 		goto free_press_irq;
 	}
 
+	err = device_create_file(&pdev->dev, &dev_attr_debounce_us);
+	if (err < 0) {
+		dev_err(&pdev->dev,
+				"dev file creation for debounce failed: %d\n",
+				err);
+		goto free_rel_irq;
+	}
+
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
 
 	return 0;
 
+free_rel_irq:
+	free_irq(key_release_irq, pwrkey);
 free_press_irq:
-	free_irq(key_press_irq, NULL);
+	free_irq(key_press_irq, pwrkey);
 unreg_input_dev:
 	platform_set_drvdata(pdev, NULL);
 	input_unregister_device(pwr);
@@ -224,6 +285,7 @@
 
 	device_init_wakeup(&pdev->dev, 0);
 
+	device_remove_file(&pdev->dev, &dev_attr_debounce_us);
 	free_irq(key_press_irq, pwrkey);
 	free_irq(key_release_irq, pwrkey);
 	input_unregister_device(pwrkey->pwr);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index f10f433..f671806 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1389,7 +1389,8 @@
 	}
 	data->t9_max_reportid = t9_object->max_reportid;
 	data->t9_min_reportid = t9_object->max_reportid -
-					t9_object->num_report_ids + 1;
+					(t9_object->num_report_ids *
+					(t9_object->instances + 1)) + 1;
 
 	if (data->pdata->key_codes) {
 		t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
@@ -1398,7 +1399,8 @@
 		else {
 			data->t15_max_reportid = t15_object->max_reportid;
 			data->t15_min_reportid = t15_object->max_reportid -
-						t15_object->num_report_ids + 1;
+					(t15_object->num_report_ids *
+					(t15_object->instances + 1)) + 1;
 		}
 	}
 
@@ -1409,7 +1411,8 @@
 	else {
 		data->t42_max_reportid = t42_object->max_reportid;
 		data->t42_min_reportid = t42_object->max_reportid -
-					t42_object->num_report_ids + 1;
+					(t42_object->num_report_ids *
+					(t42_object->instances + 1)) + 1;
 	}
 
 	return 0;
@@ -2231,6 +2234,14 @@
 		}
 	}
 
+	/* calibrate */
+	if (data->pdata->need_calibration) {
+		error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+					MXT_COMMAND_CALIBRATE, 1);
+		if (error < 0)
+			dev_dbg(dev, "sending calibration command failed\n");
+	}
+
 	mutex_unlock(&input_dev->mutex);
 
 	return 0;
@@ -2447,6 +2458,9 @@
 			return -EINVAL;
 	}
 
+	/* need calibration during wakeup? */
+	pdata->need_calibration = of_property_read_bool(np,
+					"atmel,need-calibration");
 	/* config array size */
 	pdata->config_array_size = 0;
 	temp = NULL;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f867dcb..ec3429b 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092
 	select IOMMU_API
 	help
 	  Support for the IOMMUs found on certain Qualcomm SOCs.
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index c7f6b82..f49d009 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -169,8 +169,10 @@
 	mb();
 }
 
-static void __program_iommu(void __iomem *base, int smt_size)
+static void __program_iommu(void __iomem *base, int smt_size,
+			    struct msm_iommu_bfb_settings *bfb_settings)
 {
+	int i;
 	__reset_iommu(base, smt_size);
 
 	SET_CR0_SMCFCFG(base, 1);
@@ -181,6 +183,12 @@
 	SET_CR0_GFIE(base, 1);
 	SET_CR0_GFRE(base, 1);
 	SET_CR0_CLIENTPD(base, 0);
+
+	if (bfb_settings)
+		for (i = 0; i < bfb_settings->length; i++)
+			SET_GLOBAL_REG(base, bfb_settings->regs[i],
+					     bfb_settings->data[i]);
+
 	mb();	/* Make sure writes complete before returning */
 }
 
@@ -200,6 +208,17 @@
 	mb();
 }
 
+static void __release_smg(void __iomem *base, int ctx, int smt_size)
+{
+	int i;
+
+	/* Invalidate any SMGs associated with this context */
+	for (i = 0; i < smt_size; i++)
+		if (GET_SMR_VALID(base, i) &&
+		    GET_S2CR_CBNDX(base, i) == ctx)
+			SET_SMR_VALID(base, i, 0);
+}
+
 static void __program_context(void __iomem *base, int ctx, int ncb,
 				phys_addr_t pgtable, int redirect,
 				u32 *sids, int len, int smt_size)
@@ -416,7 +435,8 @@
 	}
 
 	if (!msm_iommu_ctx_attached(dev->parent))
-		__program_iommu(iommu_drvdata->base, iommu_drvdata->nsmr);
+		__program_iommu(iommu_drvdata->base, iommu_drvdata->nsmr,
+				iommu_drvdata->bfb_settings);
 
 	__program_context(iommu_drvdata->base, ctx_drvdata->num,
 		iommu_drvdata->ncb, __pa(priv->pt.fl_table),
@@ -458,6 +478,9 @@
 		GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
 
 	__reset_context(iommu_drvdata->base, ctx_drvdata->num);
+	__release_smg(iommu_drvdata->base, ctx_drvdata->num,
+		      iommu_drvdata->nsmr);
+
 	__disable_clocks(iommu_drvdata);
 
 	regulator_disable(iommu_drvdata->gdsc);
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 8c26f95..237d601 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -29,6 +29,66 @@
 #include <mach/iommu_hw-v2.h>
 #include <mach/iommu.h>
 
+static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
+				    struct msm_iommu_drvdata *drvdata)
+{
+	struct msm_iommu_bfb_settings *bfb_settings;
+	u32 nreg, nval;
+	int ret, i;
+
+	/*
+	 * It is not valid for a device to have the qcom,iommu-bfb-regs
+	 * property but not the qcom,iommu-bfb-data property, and vice versa.
+	 */
+	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-regs", &nreg)) {
+		if (of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data",
+				    &nval))
+			return -EINVAL;
+		return 0;
+	}
+
+	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data", &nval))
+		return -EINVAL;
+
+	if (nreg >= sizeof(bfb_settings->regs))
+		return -EINVAL;
+
+	if (nval >= sizeof(bfb_settings->data))
+		return -EINVAL;
+
+	if (nval != nreg)
+		return -EINVAL;
+
+	bfb_settings = devm_kzalloc(&pdev->dev, sizeof(*bfb_settings),
+				    GFP_KERNEL);
+	if (!bfb_settings)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(pdev->dev.of_node,
+					 "qcom,iommu-bfb-regs",
+					 bfb_settings->regs,
+					 nreg / sizeof(*bfb_settings->regs));
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32_array(pdev->dev.of_node,
+					 "qcom,iommu-bfb-data",
+					 bfb_settings->data,
+					 nval / sizeof(*bfb_settings->data));
+	if (ret)
+		return ret;
+
+	bfb_settings->length = nreg / sizeof(*bfb_settings->regs);
+
+	for (i = 0; i < bfb_settings->length; i++)
+		if (bfb_settings->regs[i] < IMPLDEF_OFFSET ||
+		    bfb_settings->regs[i] >= IMPLDEF_OFFSET + IMPLDEF_LENGTH)
+			return -EINVAL;
+
+	drvdata->bfb_settings = bfb_settings;
+	return 0;
+}
+
 static int msm_iommu_parse_dt(struct platform_device *pdev,
 				struct msm_iommu_drvdata *drvdata)
 {
@@ -40,6 +100,10 @@
 	if (ret)
 		goto fail;
 
+	ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
+	if (ret)
+		goto fail;
+
 	ret = of_property_read_u32(pdev->dev.of_node, "qcom,iommu-smt-size",
 				   &nsmr);
 	if (ret)
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index f42fb5e..13493b8 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/leds.h>
 #include <linux/err.h>
+#include <linux/spinlock.h>
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 #include <linux/spmi.h>
@@ -163,7 +164,7 @@
 	int			id;
 	u16			base;
 	u8			reg;
-	struct mutex		lock;
+	spinlock_t		lock;
 	struct wled_config_data *wled_cfg;
 	int			max_current;
 	bool			default_on;
@@ -299,7 +300,7 @@
 		return;
 	}
 
-	mutex_lock(&led->lock);
+	spin_lock(&led->lock);
 	led->cdev.brightness = value;
 
 	switch (led->id) {
@@ -313,7 +314,7 @@
 		dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
 		break;
 	}
-	mutex_unlock(&led->lock);
+	spin_unlock(&led->lock);
 }
 
 static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
@@ -653,7 +654,7 @@
 		return -EINVAL;
 	}
 
-	mutex_init(&led->lock);
+	spin_lock_init(&led->lock);
 
 	rc =  qpnp_led_initialize(led);
 	if (rc < 0)
@@ -680,7 +681,6 @@
 	return 0;
 
 fail_id_check:
-	mutex_destroy(&led->lock);
 	led_classdev_unregister(&led->cdev);
 	return rc;
 }
@@ -689,7 +689,6 @@
 {
 	struct qpnp_led_data *led  = dev_get_drvdata(&spmi->dev);
 
-	mutex_destroy(&led->lock);
 	led_classdev_unregister(&led->cdev);
 
 	return 0;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 7435ab2..18c3767 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -812,7 +812,7 @@
 		*kernel_mem = NULL;
 	} else {
 		*kernel_mem = ion_map_kernel(mpq_demux->ion_client,
-						ion_handle, ionflag);
+						ion_handle);
 		if (*kernel_mem == NULL) {
 			MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
 				__func__);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index af4c2c9..eb16f2d 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1940,7 +1940,7 @@
 		}
 
 		/* Check for Bahama V2 variant*/
-		if (bahama_version == 0x09)	{
+		if ((bahama_version == 0x09) || (bahama_version == 0x0a)) {
 
 			/* In case of Bahama v2, forcefully enable the
 			 * internal analog and digital voltage controllers
@@ -2179,7 +2179,8 @@
 	/* Set the index based on the bt status*/
 	index = bt_status ?  1 : 0;
 	/* Check for Bahama's existance and Bahama V2 variant*/
-	if (bahama_present && (bahama_version == 0x09))   {
+	if (bahama_present
+		&& (bahama_version == 0x09 || bahama_version == 0x0a))   {
 		radio->marimba->mod_id = SLAVE_ID_BAHAMA;
 		/* actual value itself used as mask*/
 		retval = marimba_write_bit_mask(radio->marimba,
@@ -4149,7 +4150,7 @@
 
 	/* use xfr for interrupt setup */
     if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
-		|| radio->chipID == BAHAMA_2_0) {
+		|| radio->chipID == BAHAMA_2_0 || radio->chipID == BAHAMA_2_1) {
 		FMDBG("Setting interrupts\n");
 		retval =  sync_write_xfr(radio, INT_CTRL, int_ctrl);
 	/* use register write to setup interrupts */
@@ -4175,7 +4176,8 @@
 	*  registers and it is not valid for MBA 2.1
 	*/
 	if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
-		&& (radio->chipID != BAHAMA_2_0))
+		&& (radio->chipID != BAHAMA_2_0)
+		&& (radio->chipID != BAHAMA_2_1))
 		tavarua_handle_interrupts(radio);
 
 	return retval;
@@ -4208,7 +4210,7 @@
 	/* use xfr for interrupt setup */
 	wait_timeout = 100;
 	if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
-		|| radio->chipID == BAHAMA_2_0)
+		|| radio->chipID == BAHAMA_2_0 || radio->chipID == BAHAMA_2_1)
 		retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
 	/* use register write to setup interrupts */
 	else
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 27ebac5..9e4fcd1 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -376,81 +376,67 @@
 {
 	int i;
 	int32_t rc = -EFAULT;
-	if (client->cci_client) {
-		struct msm_camera_cci_ctrl cci_ctrl;
-		cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
-		cci_ctrl.cci_info = client->cci_client;
-		cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
-		cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
-		cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
-		cci_ctrl.cfg.cci_i2c_write_cfg.size = size;
-		rc = v4l2_subdev_call(client->cci_client->cci_subdev,
-				core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
-		CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
-		rc = cci_ctrl.status;
-	} else {
-		for (i = 0; i < size; i++) {
-			enum msm_camera_i2c_data_type dt;
-			if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
-				rc = msm_camera_i2c_poll(client,
+	for (i = 0; i < size; i++) {
+		enum msm_camera_i2c_data_type dt;
+		if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
+			rc = msm_camera_i2c_poll(client,
+				reg_conf_tbl->reg_addr,
+				reg_conf_tbl->reg_data,
+				reg_conf_tbl->dt);
+		} else {
+			if (reg_conf_tbl->dt == 0)
+				dt = data_type;
+			else
+				dt = reg_conf_tbl->dt;
+			switch (dt) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+				rc = msm_camera_i2c_write(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data, dt);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_MASK:
+				rc = msm_camera_i2c_set_mask(client,
 					reg_conf_tbl->reg_addr,
 					reg_conf_tbl->reg_data,
-					reg_conf_tbl->dt);
-			} else {
-				if (reg_conf_tbl->dt == 0)
-					dt = data_type;
-				else
-					dt = reg_conf_tbl->dt;
-				switch (dt) {
-				case MSM_CAMERA_I2C_BYTE_DATA:
-				case MSM_CAMERA_I2C_WORD_DATA:
-					rc = msm_camera_i2c_write(
-						client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data, dt);
-					break;
-				case MSM_CAMERA_I2C_SET_BYTE_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_BYTE_DATA, 1);
-					break;
-				case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_BYTE_DATA, 0);
-					break;
-				case MSM_CAMERA_I2C_SET_WORD_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_WORD_DATA, 1);
-					break;
-				case MSM_CAMERA_I2C_UNSET_WORD_MASK:
-					rc = msm_camera_i2c_set_mask(client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						MSM_CAMERA_I2C_WORD_DATA, 0);
-					break;
-				case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
-					rc = msm_camera_i2c_set_write_mask_data(
-						client,
-						reg_conf_tbl->reg_addr,
-						reg_conf_tbl->reg_data,
-						reg_conf_tbl->mask,
-						MSM_CAMERA_I2C_BYTE_DATA);
-					break;
-				default:
-					pr_err("%s: Unsupport data type: %d\n",
-						__func__, dt);
-					break;
-				}
-			}
-			if (rc < 0)
+					MSM_CAMERA_I2C_BYTE_DATA, 1);
 				break;
-			reg_conf_tbl++;
+			case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+				rc = msm_camera_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_WORD_MASK:
+				rc = msm_camera_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 1);
+				break;
+			case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+				rc = msm_camera_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+				rc = msm_camera_i2c_set_write_mask_data(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					reg_conf_tbl->mask,
+					MSM_CAMERA_I2C_BYTE_DATA);
+				break;
+			default:
+				pr_err("%s: Unsupport data type: %d\n",
+					__func__, dt);
+				break;
+			}
 		}
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
 	}
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 2d9296c..17303dd 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -210,11 +210,13 @@
 	int dirty;
 	int node_type;
 	struct timeval timestamp;
+	uint32_t frame_id;
 };
 
 struct msm_cam_timestamp {
 	uint8_t present;
 	struct timeval timestamp;
+	uint32_t frame_id;
 };
 
 struct msm_cam_buf_map_info {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 1e17c5c..77922e2 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -148,6 +148,8 @@
 			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_RDI1;
 		else
 			image_mode = -1;
+	} else if (VFE_MSG_V2X_LIVESHOT_PRIMARY == vfe_msg) {
+			image_mode = MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT;
 	} else
 		image_mode = -1;
 
@@ -709,8 +711,12 @@
 
 	int rc = -EINVAL;
 	void __user *argp = (void __user *)arg;
-	struct v4l2_subdev *sd = pmctl->vfe_sdev;
-
+	struct v4l2_subdev *sd;
+	if (!pmctl->vfe_sdev) {
+		pr_err("%s vfe subdev is NULL\n", __func__);
+		return -ENXIO;
+	}
+	sd = pmctl->vfe_sdev;
 	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
 	switch (cmd) {
 	case MSM_CAM_IOCTL_CONFIG_VFE:
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 3083bb2..2919d23 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -434,7 +434,11 @@
 		D("%s Copying timestamp as %ld.%ld", __func__,
 			cam_ts->timestamp.tv_sec, cam_ts->timestamp.tv_usec);
 		buf->vidbuf.v4l2_buf.timestamp = cam_ts->timestamp;
+		buf->vidbuf.v4l2_buf.sequence  = cam_ts->frame_id;
 	}
+	D("%s Notify user about buffer %d image_mode %d frame_id %d", __func__,
+		buf->vidbuf.v4l2_buf.index, pcam_inst->image_mode,
+		buf->vidbuf.v4l2_buf.sequence);
 	vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE);
 	return 0;
 }
@@ -557,37 +561,53 @@
 	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
 	int idx;
 
-	/* Valid image mode. Search the mctl node first.
-	 * If mctl node doesnt have the instance, then
-	 * search in the user's video node */
-	if (pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_THUMB
-		|| pmctl->vfe_output_mode == VFE_OUTPUTS_THUMB_AND_MAIN
-		|| pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_PREVIEW) {
-		if (pcam->mctl_node.dev_inst_map[img_mode]
-		&& is_buffer_queued(pcam, img_mode)) {
-			idx = pcam->mctl_node.dev_inst_map[img_mode]->my_index;
-			pcam_inst = pcam->mctl_node.dev_inst[idx];
-			D("%s Found instance %p in mctl node device\n",
+		/* Valid image mode. Search the mctl node first.
+		 * If mctl node doesnt have the instance, then
+		 * search in the user's video node */
+		if (pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_THUMB
+		|| pmctl->vfe_output_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
+			if (pcam->mctl_node.dev_inst_map[img_mode]
+			&& is_buffer_queued(pcam, img_mode)) {
+				idx = pcam->mctl_node.dev_inst_map[img_mode]
+							->my_index;
+				pcam_inst = pcam->mctl_node.dev_inst[idx];
+				D("%s Found instance %p in mctl node device\n",
+				  __func__, pcam_inst);
+			} else if (pcam->dev_inst_map[img_mode]) {
+				idx = pcam->dev_inst_map[img_mode]->my_index;
+				pcam_inst = pcam->dev_inst[idx];
+				D("%s Found instance %p in video device\n",
 				__func__, pcam_inst);
-		} else if (pcam->dev_inst_map[img_mode]) {
-			idx = pcam->dev_inst_map[img_mode]->my_index;
-			pcam_inst = pcam->dev_inst[idx];
-			D("%s Found instance %p in video device\n",
+			}
+		} else if (img_mode == MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT) {
+				img_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+			if (pcam->mctl_node.dev_inst_map[img_mode] &&
+					is_buffer_queued(pcam, img_mode)) {
+				idx = pcam->mctl_node.dev_inst_map[img_mode]
+							->my_index;
+				pcam_inst = pcam->mctl_node.dev_inst[idx];
+				D("%s Found instance %p in mctl node device\n",
+				  __func__, pcam_inst);
+			} else if (pcam->dev_inst_map[img_mode]) {
+				idx = pcam->dev_inst_map[img_mode]->my_index;
+				pcam_inst = pcam->dev_inst[idx];
+				D("%s Found instance %p in video device\n",
 				__func__, pcam_inst);
+			}
+		} else {
+			if (pcam->mctl_node.dev_inst_map[img_mode]) {
+				idx = pcam->mctl_node.dev_inst_map[img_mode]
+				->my_index;
+				pcam_inst = pcam->mctl_node.dev_inst[idx];
+				D("%s Found instance %p in mctl node device\n",
+				__func__, pcam_inst);
+			} else if (pcam->dev_inst_map[img_mode]) {
+				idx = pcam->dev_inst_map[img_mode]->my_index;
+				pcam_inst = pcam->dev_inst[idx];
+				D("%s Found instance %p in video device\n",
+					__func__, pcam_inst);
+			}
 		}
-	} else {
-		if (pcam->mctl_node.dev_inst_map[img_mode]) {
-			idx = pcam->mctl_node.dev_inst_map[img_mode]->my_index;
-			pcam_inst = pcam->mctl_node.dev_inst[idx];
-			D("%s Found instance %p in mctl node device\n",
-				__func__, pcam_inst);
-		} else if (pcam->dev_inst_map[img_mode]) {
-			idx = pcam->dev_inst_map[img_mode]->my_index;
-			pcam_inst = pcam->dev_inst[idx];
-			D("%s Found instance %p in video device\n",
-				__func__, pcam_inst);
-		}
-	}
 	return pcam_inst;
 }
 
@@ -805,6 +825,7 @@
 		__func__, pcam_inst, frame->ch_paddr[0], ret_frame->dirty);
 	cam_ts.present = 1;
 	cam_ts.timestamp = ret_frame->timestamp;
+	cam_ts.frame_id   = ret_frame->frame_id;
 	if (ret_frame->dirty)
 		/* the frame is dirty, not going to disptach to app */
 		rc = msm_mctl_release_free_buf(pmctl, pcam_inst, frame);
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index a114b37..105426e 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -636,6 +636,9 @@
 	ret_frame.dirty = dirty;
 	ret_frame.node_type = 0;
 	ret_frame.timestamp = frame.timestamp;
+	ret_frame.frame_id   = frame.frame_id;
+	D("%s frame_id: %d buffer idx %d\n", __func__,
+		frame.frame_id, frame.buf_idx);
 	rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
 	return rc;
 }
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index f5c9a73..63cf38e 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -1143,18 +1143,6 @@
 			sensordata->pdata[i].csid_core);
 	}
 
-	rc = of_property_read_u32_array(of_node, "qcom,is-vpe", val_array,
-		count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		sensordata->pdata[i].is_vpe = val_array[i];
-		CDBG("%s csi_data[%d].is_vpe = %d\n", __func__, i,
-			sensordata->pdata[i].is_vpe);
-	}
-
 	pinfo->csi_lane_params = kzalloc(
 		sizeof(struct msm_camera_csi_lane_params), GFP_KERNEL);
 	if (!pinfo->csi_lane_params) {
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index cba9538..c952f7b 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1219,11 +1219,52 @@
 	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
 };
 
+static const struct of_device_id mt9m114_dt_match[] = {
+	{.compatible = "qcom,mt9m114", .data = &mt9m114_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mt9m114_dt_match);
+
+static struct platform_driver mt9m114_platform_driver = {
+	.driver = {
+		.name = "qcom,mt9m114",
+		.owner = THIS_MODULE,
+		.of_match_table = mt9m114_dt_match,
+	},
+};
+
+static int32_t mt9m114_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(mt9m114_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
 static int __init msm_sensor_init_module(void)
 {
+	int32_t rc = 0;
+	rc = platform_driver_probe(&mt9m114_platform_driver,
+		mt9m114_platform_probe);
+	if (!rc)
+		return rc;
 	return i2c_add_driver(&mt9m114_i2c_driver);
 }
 
+
+static void __exit msm_sensor_exit_module(void)
+{
+	if (mt9m114_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&mt9m114_s_ctrl);
+		platform_driver_unregister(&mt9m114_platform_driver);
+	} else {
+		i2c_del_driver(&mt9m114_i2c_driver);
+	}
+	return;
+}
+
 static struct v4l2_subdev_core_ops mt9m114_subdev_core_ops = {
 	.s_ctrl = msm_sensor_v4l2_s_ctrl,
 	.queryctrl = msm_sensor_v4l2_query_ctrl,
@@ -1286,5 +1327,6 @@
 };
 
 module_init(msm_sensor_init_module);
+module_exit(msm_sensor_exit_module);
 MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 74dd3f2..84aaa69 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -311,7 +311,7 @@
 	if (command->length > 0) {
 		command->value =
 			g_server_dev.server_queue[command->queue_idx].ctrl_data;
-		if (command->length > max_control_command_size) {
+		if (command->length > MAX_SERVER_PAYLOAD_LENGTH) {
 			pr_err("%s: user data %d is too big (max %d)\n",
 				__func__, command->length,
 				max_control_command_size);
@@ -476,20 +476,22 @@
 		struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
 {
 	struct msm_ctrl_cmd ctrlcmd;
-	void *temp_data;
+	void *temp_data = NULL;
 	int rc;
-	temp_data = kzalloc(ioctl_ptr->len, GFP_KERNEL);
-	if (!temp_data) {
-		pr_err("%s could not allocate memory\n", __func__);
-		rc = -ENOMEM;
-		goto end;
-	}
-	if (copy_from_user((void *)temp_data,
-		(void __user *)ioctl_ptr->ioctl_ptr,
-		ioctl_ptr->len)) {
-		ERR_COPY_FROM_USER();
-		rc = -EFAULT;
-		goto copy_from_user_failed;
+	if (ioctl_ptr->len > 0) {
+		temp_data = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!temp_data) {
+			pr_err("%s could not allocate memory\n", __func__);
+			rc = -ENOMEM;
+			goto end;
+		}
+		if (copy_from_user((void *)temp_data,
+			(void __user *)ioctl_ptr->ioctl_ptr,
+			ioctl_ptr->len)) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+			goto copy_from_user_failed;
+		}
 	}
 
 	mutex_lock(&pcam->vid_lock);
@@ -505,6 +507,16 @@
 	rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
 	if (rc < 0)
 		pr_err("%s: send event failed\n", __func__);
+	else {
+		if (ioctl_ptr->len > 0) {
+			if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+				(void *)temp_data,
+				ioctl_ptr->len)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+			}
+		}
+	}
 	mutex_unlock(&pcam->vid_lock);
 
 	kfree(temp_data);
@@ -1519,7 +1531,12 @@
 	pcam->server_queue_idx = server_q_idx;
 	queue = &g_server_dev.server_queue[server_q_idx];
 	queue->ctrl_data = kzalloc(sizeof(uint8_t) *
-			max_control_command_size, GFP_KERNEL);
+			MAX_SERVER_PAYLOAD_LENGTH, GFP_KERNEL);
+	if (queue->ctrl_data == NULL) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto error;
+	}
 	msm_queue_init(&queue->ctrl_q, "control");
 	msm_queue_init(&queue->eventData_q, "eventdata");
 	queue->queue_active = 1;
@@ -2523,7 +2540,11 @@
 	*p_qidx = server_q_idx;
 	queue = &g_server_dev.server_queue[server_q_idx];
 	queue->ctrl_data = kzalloc(sizeof(uint8_t) *
-		max_control_command_size, GFP_KERNEL);
+		MAX_SERVER_PAYLOAD_LENGTH, GFP_KERNEL);
+	if (!queue->ctrl_data) {
+		pr_err("%s: Could not find memory\n", __func__);
+		return -ENOMEM;
+	}
 	msm_queue_init(&queue->ctrl_q, "control");
 	msm_queue_init(&queue->eventData_q, "eventdata");
 	queue->queue_active = 1;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 6e22388..db0db36 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -587,6 +587,25 @@
 	atomic_set(&share_ctrl->handle_common_irq, 1);
 }
 
+static void axi_clear_all_interrupts(struct vfe_share_ctrl_t *share_ctrl)
+{
+	atomic_set(&share_ctrl->handle_common_irq, 0);
+	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+		share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+		share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+		share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+		share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	/* Ensure the write order while writing
+	*to the command register using the barrier */
+	msm_camera_io_w_mb(1,
+		share_ctrl->vfebase + VFE_IRQ_CMD);
+}
+
 static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl,
 	uint32_t mode)
 {
@@ -632,24 +651,6 @@
 		msm_camera_io_w(irq_mask, share_ctrl->vfebase +
 			VFE_IRQ_MASK_0);
 	}
-	/*Dont Disable for concurrent*/
-	if (share_ctrl->axi_ref_cnt == 1) {
-		atomic_set(&share_ctrl->handle_common_irq, 0);
-		msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-			share_ctrl->vfebase + VFE_IRQ_MASK_0);
-		msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-			share_ctrl->vfebase + VFE_IRQ_MASK_1);
-
-		/* clear all pending interrupts*/
-		msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-			share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
-		msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-			share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
-		/* Ensure the write order while writing
-		*to the command register using the barrier */
-		msm_camera_io_w_mb(1,
-			share_ctrl->vfebase + VFE_IRQ_CMD);
-	}
 }
 
 static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
@@ -5554,6 +5555,8 @@
 	axi_ctrl->share_ctrl->axi_ref_cnt--;
 	if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
 		return;
+
+	axi_clear_all_interrupts(axi_ctrl->share_ctrl);
 	axi_ctrl->share_ctrl->dual_enabled = 0;
 	disable_irq(axi_ctrl->vfeirq->start);
 	tasklet_kill(&axi_ctrl->vfe32_tasklet);
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index 9deae65..6440b8e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -836,7 +836,12 @@
 				kfree(data);
 				return;
 			}
-			free_buf = vfe2x_check_free_buffer(
+			if (vfe2x_ctrl->liveshot_enabled)
+				free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_V2X_LIVESHOT_PRIMARY);
+			else
+				free_buf = vfe2x_check_free_buffer(
 					VFE_MSG_OUTPUT_IRQ,
 					VFE_MSG_OUTPUT_PRIMARY);
 			CDBG("free_buf = %x\n",
@@ -1353,12 +1358,14 @@
 
 	vfe2x_subdev_notify(id, path);
 	if (op_mode & SNAPSHOT_MASK_MODE) {
-		if (path == VFE_MSG_OUTPUT_PRIMARY)
+		if (path == VFE_MSG_OUTPUT_PRIMARY ||
+				path == VFE_MSG_V2X_LIVESHOT_PRIMARY)
 			outch = &vfe2x_ctrl->snap;
 		else if (path == VFE_MSG_OUTPUT_SECONDARY)
 			outch = &vfe2x_ctrl->thumb;
 	} else {
-		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+		if (path == VFE_MSG_OUTPUT_PRIMARY ||
+				path == VFE_MSG_V2X_LIVESHOT_PRIMARY) {
 			if (vfe2x_ctrl->zsl_mode)
 				outch = &vfe2x_ctrl->zsl_prim;
 			else
@@ -1380,12 +1387,14 @@
 	vfe2x_subdev_notify(id, path);
 	CDBG("Opmode = %d\n", op_mode);
 	if (op_mode & SNAPSHOT_MASK_MODE) {
-		if (path == VFE_MSG_OUTPUT_PRIMARY)
+		if (path == VFE_MSG_OUTPUT_PRIMARY ||
+				path == VFE_MSG_V2X_LIVESHOT_PRIMARY)
 			outch = &vfe2x_ctrl->snap;
 		else if (path == VFE_MSG_OUTPUT_SECONDARY)
 			outch = &vfe2x_ctrl->thumb;
 	} else {
-		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+		if (path == VFE_MSG_OUTPUT_PRIMARY ||
+				path == VFE_MSG_V2X_LIVESHOT_PRIMARY) {
 			if (vfe2x_ctrl->zsl_mode)
 				outch = &vfe2x_ctrl->zsl_prim;
 			else
@@ -1413,10 +1422,12 @@
 	if (op_mode & SNAPSHOT_MASK_MODE) {
 		if (path == VFE_MSG_OUTPUT_SECONDARY)
 			ch = &vfe2x_ctrl->thumb;
-		else if (path == VFE_MSG_OUTPUT_PRIMARY)
+		else if (path == VFE_MSG_OUTPUT_PRIMARY ||
+					path == VFE_MSG_V2X_LIVESHOT_PRIMARY)
 			ch = &vfe2x_ctrl->snap;
 	} else {
-		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+		if (path == VFE_MSG_OUTPUT_PRIMARY ||
+					path == VFE_MSG_V2X_LIVESHOT_PRIMARY) {
 			if (vfe2x_ctrl->zsl_mode)
 				ch = &vfe2x_ctrl->zsl_prim;
 			else
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 659cf7e..879418d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -210,7 +210,7 @@
 
 enum hal_mpeg4_profile {
 	HAL_MPEG4_PROFILE_SIMPLE           = 0x00000001,
-	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00000002,
+	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00000002,
 	HAL_MPEG4_PROFILE_CORE             = 0x00000004,
 	HAL_MPEG4_PROFILE_MAIN             = 0x00000008,
 	HAL_MPEG4_PROFILE_NBIT             = 0x00000010,
@@ -224,7 +224,7 @@
 	HAL_MPEG4_PROFILE_ADVANCEDCODING   = 0x00001000,
 	HAL_MPEG4_PROFILE_ADVANCEDCORE     = 0x00002000,
 	HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
-	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00008000,
+	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00008000,
 	HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
 };
 
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index bc2d2ce..09a5e32 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -1352,6 +1352,48 @@
 err_set_perf_level:
 	return rc;
 }
+
+static long venc_set_avc_delimiter(struct video_client_ctx *client_ctx,
+			__s32 flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_avc_delimiter_enable delimiter_flag;
+	if (!client_ctx)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_DELIMITER_FLAG;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_avc_delimiter_enable);
+	delimiter_flag.avc_delimiter_enable_flag = flag;
+	return vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &delimiter_flag);
+}
+
+static long venc_get_avc_delimiter(struct video_client_ctx *client_ctx,
+			__s32 *flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_avc_delimiter_enable delimiter_flag;
+	int rc = 0;
+
+	if (!client_ctx || !flag)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_DELIMITER_FLAG;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_avc_delimiter_enable);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &delimiter_flag);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Failed getting property for delimiter");
+		return rc;
+	}
+
+	*flag = delimiter_flag.avc_delimiter_enable_flag;
+	return rc;
+}
+
 static long venc_set_header_mode(struct video_client_ctx *client_ctx,
 		__s32 mode)
 {
@@ -2157,7 +2199,7 @@
 			if (rc)
 				WFD_MSG_ERR("Failed to free recon buffer\n");
 
-			if (IS_ERR_OR_NULL(
+			if (!IS_ERR_OR_NULL(
 				client_ctx->recon_buffer_ion_handle[i])) {
 				if (!inst->secure) {
 					ion_unmap_iommu(
@@ -2232,6 +2274,9 @@
 	case V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL:
 		rc = venc_set_max_perf_level(client_ctx, ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+		rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
 		rc = venc_set_entropy_mode(client_ctx, ctrl->value);
 		break;
@@ -2303,6 +2348,9 @@
 	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
 		rc = venc_get_cyclic_intra_refresh_mb(client_ctx, &ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+		rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index e6cbae3..753171c 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -1265,6 +1265,9 @@
 		}
 
 		rate = c_data->vc_format.clk_freq / 100 * 102;
+		if ((c_data->vc_format.hactive_end -
+				c_data->vc_format.hactive_start) > 539)
+			rate = 200000000;
 		rate_rc = clk_round_rate(dev->vcap_clk, rate);
 		if (rate_rc <= 0) {
 			pr_err("%s: Failed core rnd_rate\n", __func__);
@@ -1954,8 +1957,10 @@
 
 	/* init video device*/
 	vfd = video_device_alloc();
-	if (!vfd)
+	if (!vfd) {
+		ret = -ENOMEM;
 		goto deinit_vc;
+	}
 
 	*vfd = vcap_template;
 	vfd->v4l2_dev = &dev->v4l2_dev;
@@ -1969,6 +1974,7 @@
 
 	dev->vcap_wq = create_workqueue("vcap");
 	if (!dev->vcap_wq) {
+		ret = -ENOMEM;
 		pr_err("Could not create workqueue");
 		goto rel_vdev;
 	}
@@ -1976,6 +1982,8 @@
 	dev->ion_client = msm_ion_client_create(-1, "vcap");
 	if (IS_ERR((void *)dev->ion_client)) {
 		pr_err("could not get ion client");
+		ret = PTR_ERR(dev->ion_client);
+		dev->ion_client = NULL;
 		goto rel_vcap_wq;
 	}
 
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index aa39aad..a017cf2 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -304,7 +304,7 @@
 	}
 	if (irq & 0x01000000) {
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-			VCAP_VC_LINE_ERR_EVENT;
+			VCAP_VP_REG_W_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 	if (irq & 0x00020000) {
diff --git a/drivers/mfd/marimba-core.c b/drivers/mfd/marimba-core.c
index 70ec2ec..6a8ea6e 100644
--- a/drivers/mfd/marimba-core.c
+++ b/drivers/mfd/marimba-core.c
@@ -76,12 +76,16 @@
 	rc = marimba_read_bit_mask(marimba, 0x00,  &bahama_version, 1, 0x1F);
 	if (rc < 0)
 		return rc;
+	pr_debug("%s: Bahama version: 0x%x\n", __func__, bahama_version);
 	switch (bahama_version) {
 	case 0x08: /* varient of bahama v1 */
 	case 0x10:
 	case 0x00:
 		return BAHAMA_VER_1_0;
 	case 0x09: /* variant of bahama v2 */
+	case 0x0a: /* variant of bahama v2.1 */
+	/* Falling through because initialization */
+	/* and configuration for 2.0 and 2.1 are same */
 		return BAHAMA_VER_2_0;
 	default:
 		return BAHAMA_VER_UNSUPPORTED;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 4840e64..bc8eccf 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -142,7 +142,6 @@
 static DEFINE_MUTEX(pil_access_lock);
 
 static DEFINE_MUTEX(qsee_bw_mutex);
-static DEFINE_MUTEX(qsee_sfpb_bw_mutex);
 static DEFINE_MUTEX(app_access_lock);
 
 static int qsee_bw_count;
@@ -1198,28 +1197,41 @@
 	case CLK_DFAB:
 		mutex_lock(&qsee_bw_mutex);
 		if (!qsee_bw_count) {
-			ret = msm_bus_scale_client_update_request(
-					qsee_perf_client, 1);
+			if (qsee_sfpb_bw_count > 0)
+				ret = msm_bus_scale_client_update_request(
+						qsee_perf_client, 3);
+			else
+				ret = msm_bus_scale_client_update_request(
+						qsee_perf_client, 1);
 			if (ret)
 				pr_err("DFAB Bandwidth req failed (%d)\n",
 								ret);
 			else
 				qsee_bw_count++;
+		} else {
+			qsee_bw_count++;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
 	case CLK_SFPB:
-		mutex_lock(&qsee_sfpb_bw_mutex);
+		mutex_lock(&qsee_bw_mutex);
 		if (!qsee_sfpb_bw_count) {
-			ret = msm_bus_scale_client_update_request(
-					qsee_perf_client, 2);
+			if (qsee_bw_count > 0)
+				ret = msm_bus_scale_client_update_request(
+						qsee_perf_client, 3);
+			else
+				ret = msm_bus_scale_client_update_request(
+						qsee_perf_client, 2);
+
 			if (ret)
 				pr_err("SFPB Bandwidth req failed (%d)\n",
 								ret);
 			else
 				qsee_sfpb_bw_count++;
+		} else {
+			qsee_sfpb_bw_count++;
 		}
-		mutex_unlock(&qsee_sfpb_bw_mutex);
+		mutex_unlock(&qsee_bw_mutex);
 		break;
 	default:
 		pr_err("Clock type not defined\n");
@@ -1238,29 +1250,44 @@
 	switch (clk_type) {
 	case CLK_DFAB:
 		mutex_lock(&qsee_bw_mutex);
-		if (qsee_bw_count > 0) {
-			if (qsee_bw_count-- == 1) {
+		if (qsee_bw_count == 0) {
+			pr_err("Client error.Extra call to disable DFAB clk\n");
+			mutex_unlock(&qsee_bw_mutex);
+			return;
+		}
+
+		if ((qsee_bw_count > 0) && (qsee_bw_count-- == 1)) {
+			if (qsee_sfpb_bw_count > 0)
+				ret = msm_bus_scale_client_update_request(
+						qsee_perf_client, 2);
+			else
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 0);
-				if (ret)
-					pr_err("SFPB Bandwidth req fail (%d)\n",
+			if (ret)
+				pr_err("SFPB Bandwidth req fail (%d)\n",
 								ret);
-			}
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
 	case CLK_SFPB:
-		mutex_lock(&qsee_sfpb_bw_mutex);
-		if (qsee_sfpb_bw_count > 0) {
-			if (qsee_sfpb_bw_count-- == 1) {
+		mutex_lock(&qsee_bw_mutex);
+		if (qsee_sfpb_bw_count == 0) {
+			pr_err("Client error.Extra call to disable SFPB clk\n");
+			mutex_unlock(&qsee_bw_mutex);
+			return;
+		}
+		if ((qsee_sfpb_bw_count > 0) && (qsee_sfpb_bw_count-- == 1)) {
+			if (qsee_bw_count > 0)
+				ret = msm_bus_scale_client_update_request(
+						qsee_perf_client, 1);
+			else
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 0);
-				if (ret)
-					pr_err("SFPB Bandwidth req fail (%d)\n",
+			if (ret)
+				pr_err("SFPB Bandwidth req fail (%d)\n",
 								ret);
-			}
 		}
-		mutex_unlock(&qsee_sfpb_bw_mutex);
+		mutex_unlock(&qsee_bw_mutex);
 		break;
 	default:
 		pr_err("Clock type not defined\n");
@@ -1697,7 +1724,6 @@
 		mutex_unlock(&pil_access_lock);
 	}
 	kfree(data);
-	qsee_disable_clock_vote(CLK_DFAB);
 
 	return ret;
 }
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 15254fb..ebb4afe 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -76,14 +76,3 @@
 
 	  This driver is only of interest to those developing or
 	  testing a host driver. Most people should say N here.
-
-config MMC_BLOCK_TEST
-	tristate "MMC block test"
-	depends on MMC_BLOCK && IOSCHED_TEST
-	default m
-	help
-	  MMC block test can be used with test iosched to test the MMC block
-	  device.
-	  Currently used to test eMMC 4.5 features (packed commands, sanitize,
-	  BKOPs).
-
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index d55107f..c73b406 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -8,4 +8,3 @@
 
 obj-$(CONFIG_SDIO_UART)		+= sdio_uart.o
 
-obj-$(CONFIG_MMC_BLOCK_TEST)		+= mmc_block_test.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8b9d08b..a9f1b53 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -59,16 +59,12 @@
 #define INAND_CMD38_ARG_SECTRIM2 0x88
 
 #define MMC_SANITIZE_REQ_TIMEOUT 240000 /* msec */
+
 #define mmc_req_rel_wr(req)	(((req->cmd_flags & REQ_FUA) || \
 			(req->cmd_flags & REQ_META)) && \
 			(rq_data_dir(req) == WRITE))
 #define PACKED_CMD_VER		0x01
 #define PACKED_CMD_WR		0x02
-#define MMC_BLK_UPDATE_STOP_REASON(stats, reason)			\
-	do {								\
-		if (stats->enabled)					\
-			stats->pack_stop_reason[reason]++;		\
-	} while (0)
 
 static DEFINE_MUTEX(block_mutex);
 
@@ -120,15 +116,25 @@
 	struct device_attribute force_ro;
 	struct device_attribute power_ro_lock;
 	int	area_type;
-	struct device_attribute num_wr_reqs_to_start_packing;
 };
 
 static DEFINE_MUTEX(open_lock);
 
+enum mmc_blk_status {
+	MMC_BLK_SUCCESS = 0,
+	MMC_BLK_PARTIAL,
+	MMC_BLK_CMD_ERR,
+	MMC_BLK_RETRY,
+	MMC_BLK_ABORT,
+	MMC_BLK_DATA_ERR,
+	MMC_BLK_ECC_ERR,
+	MMC_BLK_NOMEDIUM,
+};
+
 enum {
-        MMC_PACKED_N_IDX = -1,
-        MMC_PACKED_N_ZERO,
-        MMC_PACKED_N_SINGLE,
+	MMC_PACKED_N_IDX = -1,
+	MMC_PACKED_N_ZERO,
+	MMC_PACKED_N_SINGLE,
 };
 
 module_param(perdev_minors, int, 0444);
@@ -136,8 +142,8 @@
 
 static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
 {
-        mqrq->packed_cmd = MMC_PACKED_NONE;
-        mqrq->packed_num = MMC_PACKED_N_ZERO;
+	mqrq->packed_cmd = MMC_PACKED_NONE;
+	mqrq->packed_num = MMC_PACKED_N_ZERO;
 }
 
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
@@ -273,38 +279,6 @@
 	return ret;
 }
 
-static ssize_t
-num_wr_reqs_to_start_packing_show(struct device *dev,
-				  struct device_attribute *attr, char *buf)
-{
-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	int num_wr_reqs_to_start_packing;
-	int ret;
-
-	num_wr_reqs_to_start_packing = md->queue.num_wr_reqs_to_start_packing;
-
-	ret = snprintf(buf, PAGE_SIZE, "%d\n", num_wr_reqs_to_start_packing);
-
-	mmc_blk_put(md);
-	return ret;
-}
-
-static ssize_t
-num_wr_reqs_to_start_packing_store(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	int value;
-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-
-	sscanf(buf, "%d", &value);
-	if (value >= 0)
-		md->queue.num_wr_reqs_to_start_packing = value;
-
-	mmc_blk_put(md);
-	return count;
-}
-
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -1162,6 +1136,7 @@
 	int err, check, status;
 	u8 ext_csd[512];
 
+	mq_rq->packed_retries--;
 	check = mmc_blk_err_check(card, areq);
 	err = get_card_status(card, &status, 0);
 	if (err) {
@@ -1170,7 +1145,7 @@
 		return MMC_BLK_ABORT;
 	}
 
-	if (status & R1_EXP_EVENT) {
+	if (status & R1_EXCEPTION_EVENT) {
 		err = mmc_send_ext_csd(card, ext_csd);
 		if (err) {
 			pr_err("%s: error %d sending ext_csd\n",
@@ -1349,136 +1324,6 @@
 	mmc_queue_bounce_pre(mqrq);
 }
 
-static void mmc_blk_write_packing_control(struct mmc_queue *mq,
-					  struct request *req)
-{
-	struct mmc_host *host = mq->card->host;
-	int data_dir;
-
-	if (!(host->caps2 & MMC_CAP2_PACKED_WR))
-		return;
-
-	/*
-	 * In case the packing control is not supported by the host, it should
-	 * not have an effect on the write packing. Therefore we have to enable
-	 * the write packing
-	 */
-	if (!(host->caps2 & MMC_CAP2_PACKED_WR_CONTROL)) {
-		mq->wr_packing_enabled = true;
-		return;
-	}
-
-	if (!req || (req && (req->cmd_flags & REQ_FLUSH))) {
-		if (mq->num_of_potential_packed_wr_reqs >
-				mq->num_wr_reqs_to_start_packing)
-			mq->wr_packing_enabled = true;
-		mq->num_of_potential_packed_wr_reqs = 0;
-		return;
-	}
-
-	data_dir = rq_data_dir(req);
-
-	if (data_dir == READ) {
-		mq->num_of_potential_packed_wr_reqs = 0;
-		mq->wr_packing_enabled = false;
-		return;
-	} else if (data_dir == WRITE) {
-		mq->num_of_potential_packed_wr_reqs++;
-	}
-
-	if (mq->num_of_potential_packed_wr_reqs >
-			mq->num_wr_reqs_to_start_packing)
-		mq->wr_packing_enabled = true;
-
-}
-
-struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(struct mmc_card *card)
-{
-	if (!card)
-		return NULL;
-
-	return &card->wr_pack_stats;
-}
-EXPORT_SYMBOL(mmc_blk_get_packed_statistics);
-
-void mmc_blk_init_packed_statistics(struct mmc_card *card)
-{
-	int max_num_of_packed_reqs = 0;
-
-	if (!card || !card->wr_pack_stats.packing_events)
-		return;
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	spin_lock(&card->wr_pack_stats.lock);
-	memset(card->wr_pack_stats.packing_events, 0,
-		(max_num_of_packed_reqs + 1) *
-	       sizeof(*card->wr_pack_stats.packing_events));
-	memset(&card->wr_pack_stats.pack_stop_reason, 0,
-		sizeof(card->wr_pack_stats.pack_stop_reason));
-	card->wr_pack_stats.enabled = true;
-	spin_unlock(&card->wr_pack_stats.lock);
-}
-EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
-
-void print_mmc_packing_stats(struct mmc_card *card)
-{
-	int i;
-	int max_num_of_packed_reqs = 0;
-
-	if ((!card) || (!card->wr_pack_stats.packing_events))
-		return;
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	spin_lock(&card->wr_pack_stats.lock);
-
-	pr_info("%s: write packing statistics:\n",
-		mmc_hostname(card->host));
-
-	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
-		if (card->wr_pack_stats.packing_events[i] != 0)
-			pr_info("%s: Packed %d reqs - %d times\n",
-				mmc_hostname(card->host), i,
-				card->wr_pack_stats.packing_events[i]);
-	}
-
-	pr_info("%s: stopped packing due to the following reasons:\n",
-		mmc_hostname(card->host));
-
-	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS])
-		pr_info("%s: %d times: exceedmax num of segments\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS]);
-	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS])
-		pr_info("%s: %d times: exceeding the max num of sectors\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS]);
-	if (card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR])
-		pr_info("%s: %d times: wrong data direction\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR]);
-	if (card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD])
-		pr_info("%s: %d times: flush or discard\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD]);
-	if (card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE])
-		pr_info("%s: %d times: empty queue\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE]);
-	if (card->wr_pack_stats.pack_stop_reason[REL_WRITE])
-		pr_info("%s: %d times: rel write\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[REL_WRITE]);
-	if (card->wr_pack_stats.pack_stop_reason[THRESHOLD])
-		pr_info("%s: %d times: Threshold\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[THRESHOLD]);
-
-	spin_unlock(&card->wr_pack_stats.lock);
-}
-EXPORT_SYMBOL(print_mmc_packing_stats);
-
 static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
 {
 	struct request_queue *q = mq->queue;
@@ -1491,7 +1336,6 @@
 	u8 put_back = 0;
 	u8 max_packed_rw = 0;
 	u8 reqs = 0;
-	struct mmc_wr_pack_stats *stats = &card->wr_pack_stats;
 
 	mmc_blk_clear_packed(mq->mqrq_cur);
 
@@ -1499,9 +1343,6 @@
 			!card->ext_csd.packed_event_en)
 		goto no_packed;
 
-	if (!mq->wr_packing_enabled)
-		goto no_packed;
-
 	if ((rq_data_dir(cur) == WRITE) &&
 			(card->host->caps2 & MMC_CAP2_PACKED_WR))
 		max_packed_rw = card->ext_csd.max_packed_writes;
@@ -1511,9 +1352,12 @@
 
 	if (mmc_req_rel_wr(cur) &&
 			(md->flags & MMC_BLK_REL_WR) &&
-			!en_rel_wr) {
+			!en_rel_wr)
 		goto no_packed;
-	}
+
+	if (mmc_large_sec(card) &&
+			!IS_ALIGNED(blk_rq_sectors(cur), 8))
+		goto no_packed;
 
 	max_blk_count = min(card->host->max_blk_count,
 			card->host->max_req_size >> 9);
@@ -1529,26 +1373,26 @@
 		phys_segments++;
 	}
 
-	spin_lock(&stats->lock);
-
 	while (reqs < max_packed_rw - 1) {
 		spin_lock_irq(q->queue_lock);
 		next = blk_fetch_request(q);
 		spin_unlock_irq(q->queue_lock);
-		if (!next) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, EMPTY_QUEUE);
+		if (!next)
+			break;
+
+		if (mmc_large_sec(card) &&
+				!IS_ALIGNED(blk_rq_sectors(next), 8)) {
+			put_back = 1;
 			break;
 		}
 
 		if (next->cmd_flags & REQ_DISCARD ||
 				next->cmd_flags & REQ_FLUSH) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, FLUSH_OR_DISCARD);
 			put_back = 1;
 			break;
 		}
 
 		if (rq_data_dir(cur) != rq_data_dir(next)) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, WRONG_DATA_DIR);
 			put_back = 1;
 			break;
 		}
@@ -1556,28 +1400,22 @@
 		if (mmc_req_rel_wr(next) &&
 				(md->flags & MMC_BLK_REL_WR) &&
 				!en_rel_wr) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, REL_WRITE);
 			put_back = 1;
 			break;
 		}
 
 		req_sectors += blk_rq_sectors(next);
 		if (req_sectors > max_blk_count) {
-			if (stats->enabled)
-				stats->pack_stop_reason[EXCEEDS_SECTORS]++;
 			put_back = 1;
 			break;
 		}
 
 		phys_segments +=  next->nr_phys_segments;
 		if (phys_segments > max_phys_segs) {
-			MMC_BLK_UPDATE_STOP_REASON(stats, EXCEEDS_SEGMENTS);
 			put_back = 1;
 			break;
 		}
 
-		if (rq_data_dir(next) == WRITE)
-			mq->num_of_potential_packed_wr_reqs++;
 		list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
 		cur = next;
 		reqs++;
@@ -1589,18 +1427,10 @@
 		spin_unlock_irq(q->queue_lock);
 	}
 
-	if (stats->enabled) {
-		if (reqs + 1 <= card->ext_csd.max_packed_writes)
-			stats->packing_events[reqs + 1]++;
-		if (reqs + 1 == max_packed_rw)
-			MMC_BLK_UPDATE_STOP_REASON(stats, THRESHOLD);
-	}
-
-	spin_unlock(&stats->lock);
-
 	if (reqs > 0) {
 		list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
 		mq->mqrq_cur->packed_num = ++reqs;
+		mq->mqrq_cur->packed_retries = reqs;
 		return reqs;
 	}
 
@@ -1617,7 +1447,7 @@
 	struct request *req = mqrq->req;
 	struct request *prq;
 	struct mmc_blk_data *md = mq->data;
-	bool do_rel_wr;
+	bool do_rel_wr, do_data_tag;
 	u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
 	u8 i = 1;
 
@@ -1634,9 +1464,15 @@
 	 */
 	list_for_each_entry(prq, &mqrq->packed_list, queuelist) {
 		do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
-		/* Argument of CMD23*/
+		do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+			(prq->cmd_flags & REQ_META) &&
+			(rq_data_dir(prq) == WRITE) &&
+			((brq->data.blocks * brq->data.blksz) >=
+			 card->ext_csd.data_tag_unit_size);
+		/* Argument of CMD23 */
 		packed_cmd_hdr[(i * 2)] =
 			(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
+			(do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
 			blk_rq_sectors(prq);
 		/* Argument of CMD18 or CMD25 */
 		packed_cmd_hdr[((i * 2)) + 1] =
@@ -1665,7 +1501,6 @@
 	brq->data.blksz = 512;
 	brq->data.blocks = mqrq->packed_blocks + 1;
 	brq->data.flags |= MMC_DATA_WRITE;
-	brq->data.fault_injected = false;
 
 	brq->stop.opcode = MMC_STOP_TRANSMISSION;
 	brq->stop.arg = 0;
@@ -1677,18 +1512,7 @@
 	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
 
 	mqrq->mmc_active.mrq = &brq->mrq;
-
-	/*
-	 * This is intended for packed commands tests usage - in case these
-	 * functions are not in use the respective pointers are NULL
-	 */
-	if (mq->err_check_fn)
-		mqrq->mmc_active.err_check = mq->err_check_fn;
-	else
-		mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
-
-	if (mq->packed_test_fn)
-		mq->packed_test_fn(mq->queue, mqrq);
+	mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
 
 	mmc_queue_bounce_pre(mqrq);
 }
@@ -1717,15 +1541,13 @@
 		} else
 			ret = blk_end_request(req, 0, brq->data.bytes_xfered);
 	} else {
-		if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+		if (mq_rq->packed_cmd == MMC_PACKED_NONE)
 			ret = blk_end_request(req, 0, brq->data.bytes_xfered);
-		}
 	}
 	return ret;
 }
 
-static int mmc_blk_end_packed_req(struct mmc_queue *mq,
-				  struct mmc_queue_req *mq_rq)
+static int mmc_blk_end_packed_req(struct mmc_queue_req *mq_rq)
 {
 	struct request *prq;
 	int idx = mq_rq->packed_fail_idx, i = 0;
@@ -1753,6 +1575,39 @@
 	mmc_blk_clear_packed(mq_rq);
 	return ret;
 }
+static void mmc_blk_abort_packed_req(struct mmc_queue_req *mq_rq)
+{
+	struct request *prq;
+
+	while (!list_empty(&mq_rq->packed_list)) {
+		prq = list_entry_rq(mq_rq->packed_list.next);
+		list_del_init(&prq->queuelist);
+		blk_end_request(prq, -EIO, blk_rq_bytes(prq));
+	}
+
+	mmc_blk_clear_packed(mq_rq);
+}
+
+static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
+				      struct mmc_queue_req *mq_rq)
+{
+	struct request *prq;
+	struct request_queue *q = mq->queue;
+
+	while (!list_empty(&mq_rq->packed_list)) {
+		prq = list_entry_rq(mq_rq->packed_list.prev);
+		if (prq->queuelist.prev != &mq_rq->packed_list) {
+			list_del_init(&prq->queuelist);
+			spin_lock_irq(q->queue_lock);
+			blk_requeue_request(mq->queue, prq);
+			spin_unlock_irq(q->queue_lock);
+		} else {
+			list_del_init(&prq->queuelist);
+		}
+	}
+
+	mmc_blk_clear_packed(mq_rq);
+}
 
 static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 {
@@ -1762,7 +1617,7 @@
 	int ret = 1, disable_multi = 0, retry = 0, type;
 	enum mmc_blk_status status;
 	struct mmc_queue_req *mq_rq;
-	struct request *req, *prq;
+	struct request *req;
 	struct mmc_async_req *areq;
 	const u8 packed_num = 2;
 	u8 reqs = 0;
@@ -1802,7 +1657,7 @@
 			mmc_blk_reset_success(md, type);
 
 			if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
-				ret = mmc_blk_end_packed_req(mq, mq_rq);
+				ret = mmc_blk_end_packed_req(mq_rq);
 				break;
 			} else {
 				ret = blk_end_request(req, 0,
@@ -1879,6 +1734,8 @@
 				mmc_start_req(card->host,
 						&mq_rq->mmc_active, NULL);
 			} else {
+				if (!mq_rq->packed_retries)
+					goto cmd_abort;
 				mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
 				mmc_start_req(card->host,
 						&mq_rq->mmc_active, NULL);
@@ -1896,12 +1753,7 @@
 			ret = blk_end_request(req, -EIO,
 					blk_rq_cur_bytes(req));
 	} else {
-		while (!list_empty(&mq_rq->packed_list)) {
-			prq = list_entry_rq(mq_rq->packed_list.next);
-			list_del_init(&prq->queuelist);
-			blk_end_request(prq, -EIO, blk_rq_bytes(prq));
-		}
-		mmc_blk_clear_packed(mq_rq);
+		mmc_blk_abort_packed_req(mq_rq);
 	}
 
  start_new_req:
@@ -1909,22 +1761,9 @@
 		/*
 		 * If current request is packed, it needs to put back.
 		 */
-		if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE) {
-			while (!list_empty(&mq->mqrq_cur->packed_list)) {
-				prq = list_entry_rq(
-					mq->mqrq_cur->packed_list.prev);
-				if (prq->queuelist.prev !=
-						&mq->mqrq_cur->packed_list) {
-					list_del_init(&prq->queuelist);
-					spin_lock_irq(mq->queue->queue_lock);
-					blk_requeue_request(mq->queue, prq);
-					spin_unlock_irq(mq->queue->queue_lock);
-				} else {
-					list_del_init(&prq->queuelist);
-				}
-			}
-			mmc_blk_clear_packed(mq->mqrq_cur);
-		}
+		if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE)
+			mmc_blk_revert_packed_req(mq, mq->mqrq_cur);
+
 		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
 		mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
 	}
@@ -1958,8 +1797,6 @@
 		goto out;
 	}
 
-	mmc_blk_write_packing_control(mq, req);
-
 	if (req && req->cmd_flags & REQ_SANITIZE) {
 		/* complete ongoing async transfer before issuing sanitize */
 		if (card->host && card->host->areq)
@@ -2191,8 +2028,6 @@
 
 	if (md) {
 		card = md->queue.card;
-		device_remove_file(disk_to_dev(md->disk),
-				   &md->num_wr_reqs_to_start_packing);
 		if (md->disk->flags & GENHD_FL_UP) {
 			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
 			if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
@@ -2260,16 +2095,6 @@
 			goto power_ro_lock_fail;
 	}
 
-	md->num_wr_reqs_to_start_packing.show =
-		num_wr_reqs_to_start_packing_show;
-	md->num_wr_reqs_to_start_packing.store =
-		num_wr_reqs_to_start_packing_store;
-	sysfs_attr_init(&md->num_wr_reqs_to_start_packing.attr);
-	md->num_wr_reqs_to_start_packing.attr.name =
-		"num_wr_reqs_to_start_packing";
-	md->num_wr_reqs_to_start_packing.attr.mode = S_IRUGO | S_IWUSR;
-	ret = device_create_file(disk_to_dev(md->disk),
-				 &md->num_wr_reqs_to_start_packing);
 	if (ret)
 		goto power_ro_lock_fail;
 
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
deleted file mode 100644
index 871675c..0000000
--- a/drivers/mmc/card/mmc_block_test.c
+++ /dev/null
@@ -1,2068 +0,0 @@
-
-/* Copyright (c) 2012, Code Aurora Forum. 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.
- *
- */
-
-/* MMC block test */
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/debugfs.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/delay.h>
-#include <linux/test-iosched.h>
-#include "queue.h"
-
-#define MODULE_NAME "mmc_block_test"
-#define TEST_MAX_SECTOR_RANGE		(600*1024*1024) /* 600 MB */
-#define TEST_MAX_BIOS_PER_REQ		120
-#define CMD23_PACKED_BIT	(1 << 30)
-#define LARGE_PRIME_1	1103515367
-#define LARGE_PRIME_2	35757
-#define PACKED_HDR_VER_MASK 0x000000FF
-#define PACKED_HDR_RW_MASK 0x0000FF00
-#define PACKED_HDR_NUM_REQS_MASK 0x00FF0000
-#define PACKED_HDR_BITS_16_TO_29_SET 0x3FFF0000
-#define SECTOR_SIZE 512
-#define NUM_OF_SECTORS_PER_BIO		((BIO_U32_SIZE * 4) / SECTOR_SIZE)
-#define BIO_TO_SECTOR(x)		(x * NUM_OF_SECTORS_PER_BIO)
-
-#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
-#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
-#define test_pr_err(fmt, args...) pr_err("%s: "fmt"\n", MODULE_NAME, args)
-
-#define SANITIZE_TEST_TIMEOUT 240000
-
-enum is_random {
-	NON_RANDOM_TEST,
-	RANDOM_TEST,
-};
-
-enum mmc_block_test_testcases {
-	/* Start of send write packing test group */
-	SEND_WRITE_PACKING_MIN_TESTCASE,
-	TEST_STOP_DUE_TO_READ = SEND_WRITE_PACKING_MIN_TESTCASE,
-	TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS,
-	TEST_STOP_DUE_TO_FLUSH,
-	TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS,
-	TEST_STOP_DUE_TO_EMPTY_QUEUE,
-	TEST_STOP_DUE_TO_MAX_REQ_NUM,
-	TEST_STOP_DUE_TO_THRESHOLD,
-	SEND_WRITE_PACKING_MAX_TESTCASE = TEST_STOP_DUE_TO_THRESHOLD,
-
-	/* Start of err check test group */
-	ERR_CHECK_MIN_TESTCASE,
-	TEST_RET_ABORT = ERR_CHECK_MIN_TESTCASE,
-	TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS,
-	TEST_RET_PARTIAL_FOLLOWED_BY_ABORT,
-	TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS,
-	TEST_RET_PARTIAL_MAX_FAIL_IDX,
-	TEST_RET_RETRY,
-	TEST_RET_CMD_ERR,
-	TEST_RET_DATA_ERR,
-	ERR_CHECK_MAX_TESTCASE = TEST_RET_DATA_ERR,
-
-	/* Start of send invalid test group */
-	INVALID_CMD_MIN_TESTCASE,
-	TEST_HDR_INVALID_VERSION = INVALID_CMD_MIN_TESTCASE,
-	TEST_HDR_WRONG_WRITE_CODE,
-	TEST_HDR_INVALID_RW_CODE,
-	TEST_HDR_DIFFERENT_ADDRESSES,
-	TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL,
-	TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL,
-	TEST_HDR_CMD23_PACKED_BIT_SET,
-	TEST_CMD23_MAX_PACKED_WRITES,
-	TEST_CMD23_ZERO_PACKED_WRITES,
-	TEST_CMD23_PACKED_BIT_UNSET,
-	TEST_CMD23_REL_WR_BIT_SET,
-	TEST_CMD23_BITS_16TO29_SET,
-	TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
-	INVALID_CMD_MAX_TESTCASE = TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
-
-	/*
-	 * Start of packing control test group.
-	 * in these next testcases the abbreviation FB = followed by
-	 */
-	PACKING_CONTROL_MIN_TESTCASE,
-	TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ =
-				PACKING_CONTROL_MIN_TESTCASE,
-	TEST_PACKING_EXP_N_OVER_TRIGGER,
-	TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ,
-	TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N,
-	TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER,
-	TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS,
-	TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS,
-	TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER,
-	TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER,
-	TEST_PACK_MIX_PACKED_NO_PACKED_PACKED,
-	TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
-	PACKING_CONTROL_MAX_TESTCASE = TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
-
-	TEST_WRITE_DISCARD_SANITIZE_READ,
-};
-
-enum mmc_block_test_group {
-	TEST_NO_GROUP,
-	TEST_GENERAL_GROUP,
-	TEST_SEND_WRITE_PACKING_GROUP,
-	TEST_ERR_CHECK_GROUP,
-	TEST_SEND_INVALID_GROUP,
-	TEST_PACKING_CONTROL_GROUP,
-};
-
-struct mmc_block_test_debug {
-	struct dentry *send_write_packing_test;
-	struct dentry *err_check_test;
-	struct dentry *send_invalid_packed_test;
-	struct dentry *random_test_seed;
-	struct dentry *packing_control_test;
-	struct dentry *discard_sanitize_test;
-};
-
-struct mmc_block_test_data {
-	/* The number of write requests that the test will issue */
-	int num_requests;
-	/* The expected write packing statistics for the current test */
-	struct mmc_wr_pack_stats exp_packed_stats;
-	/*
-	 * A user-defined seed for random choices of number of bios written in
-	 * a request, and of number of requests issued in a test
-	 * This field is randomly updated after each use
-	 */
-	unsigned int random_test_seed;
-	/* A retry counter used in err_check tests */
-	int err_check_counter;
-	/* Can be one of the values of enum test_group */
-	enum mmc_block_test_group test_group;
-	/*
-	 * Indicates if the current testcase is running with random values of
-	 * num_requests and num_bios (in each request)
-	 */
-	int is_random;
-	/* Data structure for debugfs dentrys */
-	struct mmc_block_test_debug debug;
-	/*
-	 * Data structure containing individual test information, including
-	 * self-defined specific data
-	 */
-	struct test_info test_info;
-	/* mmc block device test */
-	struct blk_dev_test_type bdt;
-};
-
-static struct mmc_block_test_data *mbtd;
-
-/*
- * A callback assigned to the packed_test_fn field.
- * Called from block layer in mmc_blk_packed_hdr_wrq_prep.
- * Here we alter the packed header or CMD23 in order to send an invalid
- * packed command to the card.
- */
-static void test_invalid_packed_cmd(struct request_queue *q,
-				    struct mmc_queue_req *mqrq)
-{
-	struct mmc_queue *mq = q->queuedata;
-	u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
-	struct request *req = mqrq->req;
-	struct request *second_rq;
-	struct test_request *test_rq;
-	struct mmc_blk_request *brq = &mqrq->brq;
-	int num_requests;
-	int max_packed_reqs;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return;
-	}
-
-	test_rq = (struct test_request *)req->elv.priv[0];
-	if (!test_rq) {
-		test_pr_err("%s: NULL test_rq", __func__);
-		return;
-	}
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	switch (mbtd->test_info.testcase) {
-	case TEST_HDR_INVALID_VERSION:
-		test_pr_info("%s: set invalid header version", __func__);
-		/* Put 0 in header version field (1 byte, offset 0 in header) */
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] & ~PACKED_HDR_VER_MASK;
-		break;
-	case TEST_HDR_WRONG_WRITE_CODE:
-		test_pr_info("%s: wrong write code", __func__);
-		/* Set R/W field with R value (1 byte, offset 1 in header) */
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] & ~PACKED_HDR_RW_MASK;
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] | 0x00000100;
-		break;
-	case TEST_HDR_INVALID_RW_CODE:
-		test_pr_info("%s: invalid r/w code", __func__);
-		/* Set R/W field with invalid value */
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] & ~PACKED_HDR_RW_MASK;
-		packed_cmd_hdr[0] = packed_cmd_hdr[0] | 0x00000400;
-		break;
-	case TEST_HDR_DIFFERENT_ADDRESSES:
-		test_pr_info("%s: different addresses", __func__);
-		second_rq = list_entry(req->queuelist.next, struct request,
-				queuelist);
-		test_pr_info("%s: test_rq->sector=%ld, second_rq->sector=%ld",
-			      __func__, (long)req->__sector,
-			     (long)second_rq->__sector);
-		/*
-		 * Put start sector of second write request in the first write
-		 * request's cmd25 argument in the packed header
-		 */
-		packed_cmd_hdr[3] = second_rq->__sector;
-		break;
-	case TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL:
-		test_pr_info("%s: request num smaller than actual" , __func__);
-		num_requests = (packed_cmd_hdr[0] & PACKED_HDR_NUM_REQS_MASK)
-									>> 16;
-		/* num of entries is decremented by 1 */
-		num_requests = (num_requests - 1) << 16;
-		/*
-		 * Set number of requests field in packed write header to be
-		 * smaller than the actual number (1 byte, offset 2 in header)
-		 */
-		packed_cmd_hdr[0] = (packed_cmd_hdr[0] &
-				     ~PACKED_HDR_NUM_REQS_MASK) + num_requests;
-		break;
-	case TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL:
-		test_pr_info("%s: request num larger than actual" , __func__);
-		num_requests = (packed_cmd_hdr[0] & PACKED_HDR_NUM_REQS_MASK)
-									>> 16;
-		/* num of entries is incremented by 1 */
-		num_requests = (num_requests + 1) << 16;
-		/*
-		 * Set number of requests field in packed write header to be
-		 * larger than the actual number (1 byte, offset 2 in header).
-		 */
-		packed_cmd_hdr[0] = (packed_cmd_hdr[0] &
-				     ~PACKED_HDR_NUM_REQS_MASK) + num_requests;
-		break;
-	case TEST_HDR_CMD23_PACKED_BIT_SET:
-		test_pr_info("%s: header CMD23 packed bit set" , __func__);
-		/*
-		 * Set packed bit (bit 30) in cmd23 argument of first and second
-		 * write requests in packed write header.
-		 * These are located at bytes 2 and 4 in packed write header
-		 */
-		packed_cmd_hdr[2] = packed_cmd_hdr[2] | CMD23_PACKED_BIT;
-		packed_cmd_hdr[4] = packed_cmd_hdr[4] | CMD23_PACKED_BIT;
-		break;
-	case TEST_CMD23_MAX_PACKED_WRITES:
-		test_pr_info("%s: CMD23 request num > max_packed_reqs",
-			      __func__);
-		/*
-		 * Set the individual packed cmd23 request num to
-		 * max_packed_reqs + 1
-		 */
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED | (max_packed_reqs + 1);
-		break;
-	case TEST_CMD23_ZERO_PACKED_WRITES:
-		test_pr_info("%s: CMD23 request num = 0", __func__);
-		/* Set the individual packed cmd23 request num to zero */
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED;
-		break;
-	case TEST_CMD23_PACKED_BIT_UNSET:
-		test_pr_info("%s: CMD23 packed bit unset", __func__);
-		/*
-		 * Set the individual packed cmd23 packed bit to 0,
-		 *  although there is a packed write request
-		 */
-		brq->sbc.arg &= ~CMD23_PACKED_BIT;
-		break;
-	case TEST_CMD23_REL_WR_BIT_SET:
-		test_pr_info("%s: CMD23 REL WR bit set", __func__);
-		/* Set the individual packed cmd23 reliable write bit */
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED | MMC_CMD23_ARG_REL_WR;
-		break;
-	case TEST_CMD23_BITS_16TO29_SET:
-		test_pr_info("%s: CMD23 bits [16-29] set", __func__);
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED |
-			PACKED_HDR_BITS_16_TO_29_SET;
-		break;
-	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
-		test_pr_info("%s: CMD23 hdr not in block count", __func__);
-		brq->sbc.arg = MMC_CMD23_ARG_PACKED |
-		((rq_data_dir(req) == READ) ? 0 : mqrq->packed_blocks);
-		break;
-	default:
-		test_pr_err("%s: unexpected testcase %d",
-			__func__, mbtd->test_info.testcase);
-		break;
-	}
-}
-
-/*
- * A callback assigned to the err_check_fn field of the mmc_request by the
- * MMC/card/block layer.
- * Called upon request completion by the MMC/core layer.
- * Here we emulate an error return value from the card.
- */
-static int test_err_check(struct mmc_card *card, struct mmc_async_req *areq)
-{
-	struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
-			mmc_active);
-	struct request_queue *req_q = test_iosched_get_req_queue();
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-	int ret = 0;
-
-	if (req_q)
-		mq = req_q->queuedata;
-	else {
-		test_pr_err("%s: NULL request_queue", __func__);
-		return 0;
-	}
-
-	if (!mq) {
-		test_pr_err("%s: %s: NULL mq", __func__,
-			mmc_hostname(card->host));
-		return 0;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	if (!mq_rq) {
-		test_pr_err("%s: %s: NULL mq_rq", __func__,
-			mmc_hostname(card->host));
-		return 0;
-	}
-
-	switch (mbtd->test_info.testcase) {
-	case TEST_RET_ABORT:
-		test_pr_info("%s: return abort", __func__);
-		ret = MMC_BLK_ABORT;
-		break;
-	case TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS:
-		test_pr_info("%s: return partial followed by success",
-			      __func__);
-		/*
-		 * Since in this testcase num_requests is always >= 2,
-		 * we can be sure that packed_fail_idx is always >= 1
-		 */
-		mq_rq->packed_fail_idx = (mbtd->num_requests / 2);
-		test_pr_info("%s: packed_fail_idx = %d"
-			, __func__, mq_rq->packed_fail_idx);
-		mq->err_check_fn = NULL;
-		ret = MMC_BLK_PARTIAL;
-		break;
-	case TEST_RET_PARTIAL_FOLLOWED_BY_ABORT:
-		if (!mbtd->err_check_counter) {
-			test_pr_info("%s: return partial followed by abort",
-				      __func__);
-			mbtd->err_check_counter++;
-			/*
-			 * Since in this testcase num_requests is always >= 3,
-			 * we have that packed_fail_idx is always >= 1
-			 */
-			mq_rq->packed_fail_idx = (mbtd->num_requests / 2);
-			test_pr_info("%s: packed_fail_idx = %d"
-				, __func__, mq_rq->packed_fail_idx);
-			ret = MMC_BLK_PARTIAL;
-			break;
-		}
-		mbtd->err_check_counter = 0;
-		mq->err_check_fn = NULL;
-		ret = MMC_BLK_ABORT;
-		break;
-	case TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS:
-		test_pr_info("%s: return partial multiple until success",
-			     __func__);
-		if (++mbtd->err_check_counter >= (mbtd->num_requests)) {
-			mq->err_check_fn = NULL;
-			mbtd->err_check_counter = 0;
-			ret = MMC_BLK_PARTIAL;
-			break;
-		}
-		mq_rq->packed_fail_idx = 1;
-		ret = MMC_BLK_PARTIAL;
-		break;
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		test_pr_info("%s: return partial max fail_idx", __func__);
-		mq_rq->packed_fail_idx = max_packed_reqs - 1;
-		mq->err_check_fn = NULL;
-		ret = MMC_BLK_PARTIAL;
-		break;
-	case TEST_RET_RETRY:
-		test_pr_info("%s: return retry", __func__);
-		ret = MMC_BLK_RETRY;
-		break;
-	case TEST_RET_CMD_ERR:
-		test_pr_info("%s: return cmd err", __func__);
-		ret = MMC_BLK_CMD_ERR;
-		break;
-	case TEST_RET_DATA_ERR:
-		test_pr_info("%s: return data err", __func__);
-		ret = MMC_BLK_DATA_ERR;
-		break;
-	default:
-		test_pr_err("%s: unexpected testcase %d",
-			__func__, mbtd->test_info.testcase);
-	}
-
-	return ret;
-}
-
-/*
- * This is a specific implementation for the get_test_case_str_fn function
- * pointer in the test_info data structure. Given a valid test_data instance,
- * the function returns a string resembling the test name, based on the testcase
- */
-static char *get_test_case_str(struct test_data *td)
-{
-	if (!td) {
-		test_pr_err("%s: NULL td", __func__);
-		return NULL;
-	}
-
-	switch (td->test_info.testcase) {
-	case TEST_STOP_DUE_TO_FLUSH:
-		return "Test stop due to flush";
-	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-		return "Test stop due to flush after max-1 reqs";
-	case TEST_STOP_DUE_TO_READ:
-		return "Test stop due to read";
-	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
-		return "Test stop due to read after max-1 reqs";
-	case TEST_STOP_DUE_TO_EMPTY_QUEUE:
-		return "Test stop due to empty queue";
-	case TEST_STOP_DUE_TO_MAX_REQ_NUM:
-		return "Test stop due to max req num";
-	case TEST_STOP_DUE_TO_THRESHOLD:
-		return "Test stop due to exceeding threshold";
-	case TEST_RET_ABORT:
-		return "Test err_check return abort";
-	case TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS:
-		return "Test err_check return partial followed by success";
-	case TEST_RET_PARTIAL_FOLLOWED_BY_ABORT:
-		return "Test err_check return partial followed by abort";
-	case TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS:
-		return "Test err_check return partial multiple until success";
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		return "Test err_check return partial max fail index";
-	case TEST_RET_RETRY:
-		return "Test err_check return retry";
-	case TEST_RET_CMD_ERR:
-		return "Test err_check return cmd error";
-	case TEST_RET_DATA_ERR:
-		return "Test err_check return data error";
-	case TEST_HDR_INVALID_VERSION:
-		return "Test invalid - wrong header version";
-	case TEST_HDR_WRONG_WRITE_CODE:
-		return "Test invalid - wrong write code";
-	case TEST_HDR_INVALID_RW_CODE:
-		return "Test invalid - wrong R/W code";
-	case TEST_HDR_DIFFERENT_ADDRESSES:
-		return "Test invalid - header different addresses";
-	case TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL:
-		return "Test invalid - header req num smaller than actual";
-	case TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL:
-		return "Test invalid - header req num larger than actual";
-	case TEST_HDR_CMD23_PACKED_BIT_SET:
-		return "Test invalid - header cmd23 packed bit set";
-	case TEST_CMD23_MAX_PACKED_WRITES:
-		return "Test invalid - cmd23 max packed writes";
-	case TEST_CMD23_ZERO_PACKED_WRITES:
-		return "Test invalid - cmd23 zero packed writes";
-	case TEST_CMD23_PACKED_BIT_UNSET:
-		return "Test invalid - cmd23 packed bit unset";
-	case TEST_CMD23_REL_WR_BIT_SET:
-		return "Test invalid - cmd23 rel wr bit set";
-	case TEST_CMD23_BITS_16TO29_SET:
-		return "Test invalid - cmd23 bits [16-29] set";
-	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
-		return "Test invalid - cmd23 header block not in count";
-	case TEST_PACKING_EXP_N_OVER_TRIGGER:
-		return "\nTest packing control - pack n";
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
-		return "\nTest packing control - pack n followed by read";
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
-		return "\nTest packing control - pack n followed by flush";
-	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
-		return "\nTest packing control - pack one followed by read";
-	case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
-		return "\nTest packing control - pack threshold";
-	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
-		return "\nTest packing control - no packing";
-	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-		return "\nTest packing control - no packing, trigger requests";
-	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
-		return "\nTest packing control - no pack, trigger-read-trigger";
-	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
-		return "\nTest packing control- no pack, trigger-flush-trigger";
-	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
-		return "\nTest packing control - mix: pack -> no pack -> pack";
-	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
-		return "\nTest packing control - mix: no pack->pack->no pack";
-	case TEST_WRITE_DISCARD_SANITIZE_READ:
-		return "\nTest write, discard, sanitize";
-	default:
-		 return "Unknown testcase";
-	}
-
-	return NULL;
-}
-
-/*
- * Compare individual testcase's statistics to the expected statistics:
- * Compare stop reason and number of packing events
- */
-static int check_wr_packing_statistics(struct test_data *td)
-{
-	struct mmc_wr_pack_stats *mmc_packed_stats;
-	struct mmc_queue *mq = td->req_q->queuedata;
-	int max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-	int i;
-	struct mmc_card *card = mq->card;
-	struct mmc_wr_pack_stats expected_stats;
-	int *stop_reason;
-	int ret = 0;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	expected_stats = mbtd->exp_packed_stats;
-
-	mmc_packed_stats = mmc_blk_get_packed_statistics(card);
-	if (!mmc_packed_stats) {
-		test_pr_err("%s: NULL mmc_packed_stats", __func__);
-		return -EINVAL;
-	}
-
-	if (!mmc_packed_stats->packing_events) {
-		test_pr_err("%s: NULL packing_events", __func__);
-		return -EINVAL;
-	}
-
-	spin_lock(&mmc_packed_stats->lock);
-
-	if (!mmc_packed_stats->enabled) {
-		test_pr_err("%s write packing statistics are not enabled",
-			     __func__);
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	stop_reason = mmc_packed_stats->pack_stop_reason;
-
-	for (i = 1; i <= max_packed_reqs; ++i) {
-		if (mmc_packed_stats->packing_events[i] !=
-		    expected_stats.packing_events[i]) {
-			test_pr_err(
-			"%s: Wrong pack stats in index %d, got %d, expected %d",
-			__func__, i, mmc_packed_stats->packing_events[i],
-			       expected_stats.packing_events[i]);
-			if (td->fs_wr_reqs_during_test)
-				goto cancel_round;
-			ret = -EINVAL;
-			goto exit_err;
-		}
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[EXCEEDS_SEGMENTS] !=
-	    expected_stats.pack_stop_reason[EXCEEDS_SEGMENTS]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason EXCEEDS_SEGMENTS %d, expected %d",
-			__func__, stop_reason[EXCEEDS_SEGMENTS],
-		       expected_stats.pack_stop_reason[EXCEEDS_SEGMENTS]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[EXCEEDS_SECTORS] !=
-	    expected_stats.pack_stop_reason[EXCEEDS_SECTORS]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason EXCEEDS_SECTORS %d, expected %d",
-			__func__, stop_reason[EXCEEDS_SECTORS],
-		       expected_stats.pack_stop_reason[EXCEEDS_SECTORS]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[WRONG_DATA_DIR] !=
-	    expected_stats.pack_stop_reason[WRONG_DATA_DIR]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason WRONG_DATA_DIR %d, expected %d",
-		       __func__, stop_reason[WRONG_DATA_DIR],
-		       expected_stats.pack_stop_reason[WRONG_DATA_DIR]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[FLUSH_OR_DISCARD] !=
-	    expected_stats.pack_stop_reason[FLUSH_OR_DISCARD]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason FLUSH_OR_DISCARD %d, expected %d",
-		       __func__, stop_reason[FLUSH_OR_DISCARD],
-		       expected_stats.pack_stop_reason[FLUSH_OR_DISCARD]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[EMPTY_QUEUE] !=
-	    expected_stats.pack_stop_reason[EMPTY_QUEUE]) {
-		test_pr_err(
-		"%s: Wrong pack stop reason EMPTY_QUEUE %d, expected %d",
-		       __func__, stop_reason[EMPTY_QUEUE],
-		       expected_stats.pack_stop_reason[EMPTY_QUEUE]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	if (mmc_packed_stats->pack_stop_reason[REL_WRITE] !=
-	    expected_stats.pack_stop_reason[REL_WRITE]) {
-		test_pr_err(
-			"%s: Wrong pack stop reason REL_WRITE %d, expected %d",
-		       __func__, stop_reason[REL_WRITE],
-		       expected_stats.pack_stop_reason[REL_WRITE]);
-		if (td->fs_wr_reqs_during_test)
-			goto cancel_round;
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-exit_err:
-	spin_unlock(&mmc_packed_stats->lock);
-	if (ret && mmc_packed_stats->enabled)
-		print_mmc_packing_stats(card);
-	return ret;
-cancel_round:
-	spin_unlock(&mmc_packed_stats->lock);
-	test_iosched_set_ignore_round(true);
-	return 0;
-}
-
-/*
- * Pseudo-randomly choose a seed based on the last seed, and update it in
- * seed_number. then return seed_number (mod max_val), or min_val.
- */
-static unsigned int pseudo_random_seed(unsigned int *seed_number,
-				       unsigned int min_val,
-				       unsigned int max_val)
-{
-	int ret = 0;
-
-	if (!seed_number)
-		return 0;
-
-	*seed_number = ((unsigned int)(((unsigned long)*seed_number *
-				(unsigned long)LARGE_PRIME_1) + LARGE_PRIME_2));
-	ret = (unsigned int)((*seed_number) % max_val);
-
-	return (ret > min_val ? ret : min_val);
-}
-
-/*
- * Given a pseudo-random seed, find a pseudo-random num_of_bios.
- * Make sure that num_of_bios is not larger than TEST_MAX_SECTOR_RANGE
- */
-static void pseudo_rnd_num_of_bios(unsigned int *num_bios_seed,
-				   unsigned int *num_of_bios)
-{
-	do {
-		*num_of_bios = pseudo_random_seed(num_bios_seed, 1,
-						  TEST_MAX_BIOS_PER_REQ);
-		if (!(*num_of_bios))
-			*num_of_bios = 1;
-	} while ((*num_of_bios) * BIO_U32_SIZE * 4 > TEST_MAX_SECTOR_RANGE);
-}
-
-/* Add a single read request to the given td's request queue */
-static int prepare_request_add_read(struct test_data *td)
-{
-	int ret;
-	int start_sec;
-
-	if (td)
-		start_sec = td->start_sector;
-	else {
-		test_pr_err("%s: NULL td", __func__);
-		return 0;
-	}
-
-	test_pr_info("%s: Adding a read request, first req_id=%d", __func__,
-		     td->wr_rd_next_req_id);
-
-	ret = test_iosched_add_wr_rd_test_req(0, READ, start_sec, 2,
-					      TEST_PATTERN_5A, NULL);
-	if (ret) {
-		test_pr_err("%s: failed to add a read request", __func__);
-		return ret;
-	}
-
-	return 0;
-}
-
-/* Add a single flush request to the given td's request queue */
-static int prepare_request_add_flush(struct test_data *td)
-{
-	int ret;
-
-	if (!td) {
-		test_pr_err("%s: NULL td", __func__);
-		return 0;
-	}
-
-	test_pr_info("%s: Adding a flush request, first req_id=%d", __func__,
-		     td->unique_next_req_id);
-	ret = test_iosched_add_unique_test_req(0, REQ_UNIQUE_FLUSH,
-				  0, 0, NULL);
-	if (ret) {
-		test_pr_err("%s: failed to add a flush request", __func__);
-		return ret;
-	}
-
-	return ret;
-}
-
-/*
- * Add num_requets amount of write requests to the given td's request queue.
- * If random test mode is chosen we pseudo-randomly choose the number of bios
- * for each write request, otherwise add between 1 to 5 bio per request.
- */
-static int prepare_request_add_write_reqs(struct test_data *td,
-					  int num_requests, int is_err_expected,
-					  int is_random)
-{
-	int i;
-	unsigned int start_sec;
-	int num_bios;
-	int ret = 0;
-	unsigned int *bio_seed = &mbtd->random_test_seed;
-
-	if (td)
-		start_sec = td->start_sector;
-	else {
-		test_pr_err("%s: NULL td", __func__);
-		return ret;
-	}
-
-	test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
-		     num_requests, td->wr_rd_next_req_id);
-
-	for (i = 1; i <= num_requests; i++) {
-		start_sec = td->start_sector + 4096 * td->num_of_write_bios;
-		if (is_random)
-			pseudo_rnd_num_of_bios(bio_seed, &num_bios);
-		else
-			/*
-			 * For the non-random case, give num_bios a value
-			 * between 1 and 5, to keep a small number of BIOs
-			 */
-			num_bios = (i%5)+1;
-
-		ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
-				start_sec, num_bios, TEST_PATTERN_5A, NULL);
-
-		if (ret) {
-			test_pr_err("%s: failed to add a write request",
-				    __func__);
-			return ret;
-		}
-	}
-	return 0;
-}
-
-/*
- * Prepare the write, read and flush requests for a generic packed commands
- * testcase
- */
-static int prepare_packed_requests(struct test_data *td, int is_err_expected,
-				   int num_requests, int is_random)
-{
-	int ret = 0;
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-	struct request_queue *req_q;
-
-	if (!td) {
-		pr_err("%s: NULL td", __func__);
-		return -EINVAL;
-	}
-
-	req_q = td->req_q;
-
-	if (!req_q) {
-		pr_err("%s: NULL request queue", __func__);
-		return -EINVAL;
-	}
-
-	mq = req_q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	if (mbtd->random_test_seed <= 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			     __func__, mbtd->random_test_seed);
-	}
-
-	mmc_blk_init_packed_statistics(mq->card);
-
-	ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
-					     is_random);
-	if (ret)
-		return ret;
-
-	/* Avoid memory corruption in upcoming stats set */
-	if (td->test_info.testcase == TEST_STOP_DUE_TO_THRESHOLD)
-		num_requests--;
-
-	memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
-		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
-	memset(mbtd->exp_packed_stats.packing_events, 0,
-		(max_packed_reqs + 1) * sizeof(u32));
-	if (num_requests <= max_packed_reqs)
-		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-
-	switch (td->test_info.testcase) {
-	case TEST_STOP_DUE_TO_FLUSH:
-	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-		ret = prepare_request_add_flush(td);
-		if (ret)
-			return ret;
-
-		mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
-		break;
-	case TEST_STOP_DUE_TO_READ:
-	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			return ret;
-
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		break;
-	case TEST_STOP_DUE_TO_THRESHOLD:
-		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-		mbtd->exp_packed_stats.packing_events[1] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[THRESHOLD] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		break;
-	case TEST_STOP_DUE_TO_MAX_REQ_NUM:
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		mbtd->exp_packed_stats.pack_stop_reason[THRESHOLD] = 1;
-		break;
-	default:
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-	}
-	mbtd->num_requests = num_requests;
-
-	return 0;
-}
-
-/*
- * Prepare the write, read and flush requests for the packing control
- * testcases
- */
-static int prepare_packed_control_tests_requests(struct test_data *td,
-			int is_err_expected, int num_requests, int is_random)
-{
-	int ret = 0;
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-	int temp_num_req = num_requests;
-	struct request_queue *req_q;
-	int test_packed_trigger;
-	int num_packed_reqs;
-
-	if (!td) {
-		test_pr_err("%s: NULL td\n", __func__);
-		return -EINVAL;
-	}
-
-	req_q = td->req_q;
-
-	if (!req_q) {
-		test_pr_err("%s: NULL request queue\n", __func__);
-		return -EINVAL;
-	}
-
-	mq = req_q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-	test_packed_trigger = mq->num_wr_reqs_to_start_packing;
-	num_packed_reqs = num_requests - test_packed_trigger;
-
-	if (mbtd->random_test_seed == 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			     __func__, mbtd->random_test_seed);
-	}
-
-	mmc_blk_init_packed_statistics(mq->card);
-
-	if (td->test_info.testcase ==
-			TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED) {
-		temp_num_req = num_requests;
-		num_requests = test_packed_trigger - 1;
-	}
-
-	/* Verify that the packing is disabled before starting the test */
-	mq->wr_packing_enabled = false;
-	mq->num_of_potential_packed_wr_reqs = 0;
-
-	if (td->test_info.testcase == TEST_PACK_MIX_PACKED_NO_PACKED_PACKED) {
-		mq->num_of_potential_packed_wr_reqs = test_packed_trigger + 1;
-		mq->wr_packing_enabled = true;
-		num_requests = test_packed_trigger + 2;
-	}
-
-	ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
-					     is_random);
-	if (ret)
-		goto exit;
-
-	if (td->test_info.testcase == TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED)
-		num_requests = temp_num_req;
-
-	memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
-		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
-	memset(mbtd->exp_packed_stats.packing_events, 0,
-		(max_packed_reqs + 1) * sizeof(u32));
-
-	switch (td->test_info.testcase) {
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
-	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
-		ret = prepare_request_add_flush(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, num_packed_reqs,
-					     is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 2;
-		break;
-	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
-		ret = prepare_request_add_flush(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, num_requests,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-		mbtd->exp_packed_stats.packing_events[num_requests-1] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		break;
-	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, num_requests,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_read(td);
-		if (ret)
-			goto exit;
-
-		ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
-						    is_err_expected, is_random);
-		if (ret)
-			goto exit;
-
-		mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
-	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-		break;
-	default:
-		mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-		mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
-	}
-	mbtd->num_requests = num_requests;
-
-exit:
-	return ret;
-}
-
-/*
- * Prepare requests for the TEST_RET_PARTIAL_FOLLOWED_BY_ABORT testcase.
- * In this testcase we have mixed error expectations from different
- * write requests, hence the special prepare function.
- */
-static int prepare_partial_followed_by_abort(struct test_data *td,
-					      int num_requests)
-{
-	int i, start_address;
-	int is_err_expected = 0;
-	int ret = 0;
-	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
-	int max_packed_reqs;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-
-	mmc_blk_init_packed_statistics(mq->card);
-
-	for (i = 1; i <= num_requests; i++) {
-		if (i > (num_requests / 2))
-			is_err_expected = 1;
-
-		start_address = td->start_sector + 4096 * td->num_of_write_bios;
-		ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
-				start_address, (i % 5) + 1, TEST_PATTERN_5A,
-				NULL);
-		if (ret) {
-			test_pr_err("%s: failed to add a write request",
-				    __func__);
-			return ret;
-		}
-	}
-
-	memset((void *)&mbtd->exp_packed_stats.pack_stop_reason, 0,
-		sizeof(mbtd->exp_packed_stats.pack_stop_reason));
-	memset(mbtd->exp_packed_stats.packing_events, 0,
-		(max_packed_reqs + 1) * sizeof(u32));
-	mbtd->exp_packed_stats.packing_events[num_requests] = 1;
-	mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
-
-	mbtd->num_requests = num_requests;
-
-	return ret;
-}
-
-/*
- * Get number of write requests for current testcase. If random test mode was
- * chosen, pseudo-randomly choose the number of requests, otherwise set to
- * two less than the packing threshold.
- */
-static int get_num_requests(struct test_data *td)
-{
-	int *seed = &mbtd->random_test_seed;
-	struct request_queue *req_q;
-	struct mmc_queue *mq;
-	int max_num_requests;
-	int num_requests;
-	int min_num_requests = 2;
-	int is_random = mbtd->is_random;
-	int max_for_double;
-	int test_packed_trigger;
-
-	req_q = test_iosched_get_req_queue();
-	if (req_q)
-		mq = req_q->queuedata;
-	else {
-		test_pr_err("%s: NULL request queue", __func__);
-		return 0;
-	}
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_num_requests = mq->card->ext_csd.max_packed_writes;
-	num_requests = max_num_requests - 2;
-	test_packed_trigger = mq->num_wr_reqs_to_start_packing;
-
-	/*
-	 * Here max_for_double is intended for packed control testcases
-	 * in which we issue many write requests. It's purpose is to prevent
-	 * exceeding max number of req_queue requests.
-	 */
-	max_for_double = max_num_requests - 10;
-
-	if (td->test_info.testcase ==
-				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
-		/* Don't expect packing, so issue up to trigger-1 reqs */
-		num_requests = test_packed_trigger - 1;
-
-	if (is_random) {
-		if (td->test_info.testcase ==
-		    TEST_RET_PARTIAL_FOLLOWED_BY_ABORT)
-			/*
-			 * Here we don't want num_requests to be less than 1
-			 * as a consequence of division by 2.
-			 */
-			min_num_requests = 3;
-
-		if (td->test_info.testcase ==
-				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
-			/* Don't expect packing, so issue up to trigger reqs */
-			max_num_requests = test_packed_trigger;
-
-		num_requests = pseudo_random_seed(seed, min_num_requests,
-						  max_num_requests - 1);
-	}
-
-	if (td->test_info.testcase ==
-				TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
-		num_requests -= test_packed_trigger;
-
-	if (td->test_info.testcase == TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N)
-		num_requests =
-		num_requests > max_for_double ? max_for_double : num_requests;
-
-	if (mbtd->test_group == TEST_PACKING_CONTROL_GROUP)
-		num_requests += test_packed_trigger;
-
-	if (td->test_info.testcase == TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS)
-		num_requests = test_packed_trigger;
-
-	return num_requests;
-}
-
-/*
- * An implementation for the prepare_test_fn pointer in the test_info
- * data structure. According to the testcase we add the right number of requests
- * and decide if an error is expected or not.
- */
-static int prepare_test(struct test_data *td)
-{
-	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
-	int max_num_requests;
-	int num_requests = 0;
-	int ret = 0;
-	int is_random = mbtd->is_random;
-	int test_packed_trigger = mq->num_wr_reqs_to_start_packing;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_num_requests = mq->card->ext_csd.max_packed_writes;
-
-	if (is_random && mbtd->random_test_seed == 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			__func__, mbtd->random_test_seed);
-	}
-
-	num_requests = get_num_requests(td);
-
-	if (mbtd->test_group == TEST_SEND_INVALID_GROUP)
-		mq->packed_test_fn =
-				test_invalid_packed_cmd;
-
-	if (mbtd->test_group == TEST_ERR_CHECK_GROUP)
-		mq->err_check_fn = test_err_check;
-
-	switch (td->test_info.testcase) {
-	case TEST_STOP_DUE_TO_FLUSH:
-	case TEST_STOP_DUE_TO_READ:
-	case TEST_RET_PARTIAL_FOLLOWED_BY_SUCCESS:
-	case TEST_RET_PARTIAL_MULTIPLE_UNTIL_SUCCESS:
-	case TEST_STOP_DUE_TO_EMPTY_QUEUE:
-	case TEST_CMD23_PACKED_BIT_UNSET:
-		ret = prepare_packed_requests(td, 0, num_requests, is_random);
-		break;
-	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
-		ret = prepare_packed_requests(td, 0, max_num_requests - 1,
-					      is_random);
-		break;
-	case TEST_RET_PARTIAL_FOLLOWED_BY_ABORT:
-		ret = prepare_partial_followed_by_abort(td, num_requests);
-		break;
-	case TEST_STOP_DUE_TO_MAX_REQ_NUM:
-	case TEST_RET_PARTIAL_MAX_FAIL_IDX:
-		ret = prepare_packed_requests(td, 0, max_num_requests,
-					      is_random);
-		break;
-	case TEST_STOP_DUE_TO_THRESHOLD:
-		ret = prepare_packed_requests(td, 0, max_num_requests + 1,
-					      is_random);
-		break;
-	case TEST_RET_ABORT:
-	case TEST_RET_RETRY:
-	case TEST_RET_CMD_ERR:
-	case TEST_RET_DATA_ERR:
-	case TEST_HDR_INVALID_VERSION:
-	case TEST_HDR_WRONG_WRITE_CODE:
-	case TEST_HDR_INVALID_RW_CODE:
-	case TEST_HDR_DIFFERENT_ADDRESSES:
-	case TEST_HDR_REQ_NUM_SMALLER_THAN_ACTUAL:
-	case TEST_HDR_REQ_NUM_LARGER_THAN_ACTUAL:
-	case TEST_CMD23_MAX_PACKED_WRITES:
-	case TEST_CMD23_ZERO_PACKED_WRITES:
-	case TEST_CMD23_REL_WR_BIT_SET:
-	case TEST_CMD23_BITS_16TO29_SET:
-	case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
-	case TEST_HDR_CMD23_PACKED_BIT_SET:
-		ret = prepare_packed_requests(td, 1, num_requests, is_random);
-		break;
-	case TEST_PACKING_EXP_N_OVER_TRIGGER:
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
-	case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
-	case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
-	case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
-	case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
-		ret = prepare_packed_control_tests_requests(td, 0, num_requests,
-			is_random);
-		break;
-	case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
-		ret = prepare_packed_control_tests_requests(td, 0,
-			max_num_requests, is_random);
-		break;
-	case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
-		ret = prepare_packed_control_tests_requests(td, 0,
-			test_packed_trigger + 1,
-					is_random);
-		break;
-	case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
-		ret = prepare_packed_control_tests_requests(td, 0, num_requests,
-			is_random);
-		break;
-	case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
-	case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
-		ret = prepare_packed_control_tests_requests(td, 0,
-			test_packed_trigger, is_random);
-		break;
-	default:
-		test_pr_info("%s: Invalid test case...", __func__);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/*
- * An implementation for the post_test_fn in the test_info data structure.
- * In our case we just reset the function pointers in the mmc_queue in order for
- * the FS to be able to dispatch it's requests correctly after the test is
- * finished.
- */
-static int post_test(struct test_data *td)
-{
-	struct mmc_queue *mq;
-
-	if (!td)
-		return -EINVAL;
-
-	mq = td->req_q->queuedata;
-
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	mq->packed_test_fn = NULL;
-	mq->err_check_fn = NULL;
-
-	return 0;
-}
-
-/*
- * This function checks, based on the current test's test_group, that the
- * packed commands capability and control are set right. In addition, we check
- * if the card supports the packed command feature.
- */
-static int validate_packed_commands_settings(void)
-{
-	struct request_queue *req_q;
-	struct mmc_queue *mq;
-	int max_num_requests;
-	struct mmc_host *host;
-
-	req_q = test_iosched_get_req_queue();
-	if (!req_q) {
-		test_pr_err("%s: test_iosched_get_req_queue failed", __func__);
-		test_iosched_set_test_result(TEST_FAILED);
-		return -EINVAL;
-	}
-
-	mq = req_q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return -EINVAL;
-	}
-
-	max_num_requests = mq->card->ext_csd.max_packed_writes;
-	host = mq->card->host;
-
-	if (!(host->caps2 && MMC_CAP2_PACKED_WR)) {
-		test_pr_err("%s: Packed Write capability disabled, exit test",
-			    __func__);
-		test_iosched_set_test_result(TEST_NOT_SUPPORTED);
-		return -EINVAL;
-	}
-
-	if (max_num_requests == 0) {
-		test_pr_err(
-		"%s: no write packing support, ext_csd.max_packed_writes=%d",
-		__func__, mq->card->ext_csd.max_packed_writes);
-		test_iosched_set_test_result(TEST_NOT_SUPPORTED);
-		return -EINVAL;
-	}
-
-	test_pr_info("%s: max number of packed requests supported is %d ",
-		     __func__, max_num_requests);
-
-	switch (mbtd->test_group) {
-	case TEST_SEND_WRITE_PACKING_GROUP:
-	case TEST_ERR_CHECK_GROUP:
-	case TEST_SEND_INVALID_GROUP:
-		/* disable the packing control */
-		host->caps2 &= ~MMC_CAP2_PACKED_WR_CONTROL;
-		break;
-	case TEST_PACKING_CONTROL_GROUP:
-		host->caps2 |=  MMC_CAP2_PACKED_WR_CONTROL;
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static void pseudo_rnd_sector_and_size(unsigned int *seed,
-				       unsigned int min_start_sector,
-				       unsigned int *start_sector,
-				       unsigned int *num_of_bios)
-{
-	unsigned int max_sec = min_start_sector + TEST_MAX_SECTOR_RANGE;
-	do {
-		*start_sector = pseudo_random_seed(seed,
-						   1, max_sec);
-		*num_of_bios = pseudo_random_seed(seed,
-						  1, TEST_MAX_BIOS_PER_REQ);
-		if (!(*num_of_bios))
-			*num_of_bios = 1;
-	} while ((*start_sector < min_start_sector) ||
-		 (*start_sector + (*num_of_bios * BIO_U32_SIZE * 4)) > max_sec);
-}
-
-/* sanitize test functions */
-static int prepare_write_discard_sanitize_read(struct test_data *td)
-{
-	unsigned int start_sector;
-	unsigned int num_of_bios = 0;
-	static unsigned int total_bios;
-	unsigned int *num_bios_seed;
-	int i = 0;
-
-	if (mbtd->random_test_seed == 0) {
-		mbtd->random_test_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_pr_info("%s: got seed from jiffies %d",
-			     __func__, mbtd->random_test_seed);
-	}
-	num_bios_seed = &mbtd->random_test_seed;
-
-	do {
-		pseudo_rnd_sector_and_size(num_bios_seed, td->start_sector,
-					   &start_sector, &num_of_bios);
-
-		/* DISCARD */
-		total_bios += num_of_bios;
-		test_pr_info("%s: discard req: id=%d, startSec=%d, NumBios=%d",
-		       __func__, td->unique_next_req_id, start_sector,
-			     num_of_bios);
-		test_iosched_add_unique_test_req(0, REQ_UNIQUE_DISCARD,
-				    start_sector, BIO_TO_SECTOR(num_of_bios),
-						 NULL);
-
-	} while (++i < (BLKDEV_MAX_RQ-10));
-
-	test_pr_info("%s: total discard bios = %d", __func__, total_bios);
-
-	test_pr_info("%s: add sanitize req", __func__);
-	test_iosched_add_unique_test_req(0, REQ_UNIQUE_SANITIZE, 0, 0, NULL);
-
-	return 0;
-}
-
-static bool message_repeat;
-static int test_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	message_repeat = 1;
-	return 0;
-}
-
-/* send_packing TEST */
-static ssize_t send_write_packing_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-
-	test_pr_info("%s: -- send_write_packing TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-
-	mbtd->test_group = TEST_SEND_WRITE_PACKING_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	if (mbtd->random_test_seed > 0)
-		test_pr_info("%s: Test seed: %d", __func__,
-			      mbtd->random_test_seed);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.post_test_fn = post_test;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = SEND_WRITE_PACKING_MIN_TESTCASE;
-		      j <= SEND_WRITE_PACKING_MAX_TESTCASE; j++) {
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	return count;
-}
-
-static ssize_t send_write_packing_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nsend_write_packing_test\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Pack due to FLUSH message\n"
-		 "- Pack due to FLUSH after threshold writes\n"
-		 "- Pack due to READ message\n"
-		 "- Pack due to READ after threshold writes\n"
-		 "- Pack due to empty queue\n"
-		 "- Pack due to threshold writes\n"
-		 "- Pack due to one over threshold writes\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations send_write_packing_test_ops = {
-	.open = test_open,
-	.write = send_write_packing_test_write,
-	.read = send_write_packing_test_read,
-};
-
-/* err_check TEST */
-static ssize_t err_check_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-
-	test_pr_info("%s: -- err_check TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-	mbtd->test_group = TEST_ERR_CHECK_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	if (mbtd->random_test_seed > 0)
-		test_pr_info("%s: Test seed: %d", __func__,
-			      mbtd->random_test_seed);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.post_test_fn = post_test;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = ERR_CHECK_MIN_TESTCASE;
-					j <= ERR_CHECK_MAX_TESTCASE ; j++) {
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				break;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	return count;
-}
-
-static ssize_t err_check_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nerr_check_TEST\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Return ABORT\n"
-		 "- Return PARTIAL followed by success\n"
-		 "- Return PARTIAL followed by abort\n"
-		 "- Return PARTIAL multiple times until success\n"
-		 "- Return PARTIAL with fail index = threshold\n"
-		 "- Return RETRY\n"
-		 "- Return CMD_ERR\n"
-		 "- Return DATA_ERR\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations err_check_test_ops = {
-	.open = test_open,
-	.write = err_check_test_write,
-	.read = err_check_test_read,
-};
-
-/* send_invalid_packed TEST */
-static ssize_t send_invalid_packed_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-	int num_of_failures = 0;
-
-	test_pr_info("%s: -- send_invalid_packed TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-	mbtd->test_group = TEST_SEND_INVALID_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	if (mbtd->random_test_seed > 0)
-		test_pr_info("%s: Test seed: %d", __func__,
-			      mbtd->random_test_seed);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.post_test_fn = post_test;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = INVALID_CMD_MIN_TESTCASE;
-				j <= INVALID_CMD_MAX_TESTCASE ; j++) {
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				num_of_failures++;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret)
-				num_of_failures++;
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	if (num_of_failures > 0) {
-		test_iosched_set_test_result(TEST_FAILED);
-		test_pr_err(
-			"There were %d failures during the test, TEST FAILED",
-			num_of_failures);
-	}
-	return count;
-}
-
-static ssize_t send_invalid_packed_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nsend_invalid_packed_TEST\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Send an invalid header version\n"
-		 "- Send the wrong write code\n"
-		 "- Send an invalid R/W code\n"
-		 "- Send wrong start address in header\n"
-		 "- Send header with block_count smaller than actual\n"
-		 "- Send header with block_count larger than actual\n"
-		 "- Send header CMD23 packed bit set\n"
-		 "- Send CMD23 with block count over threshold\n"
-		 "- Send CMD23 with block_count equals zero\n"
-		 "- Send CMD23 packed bit unset\n"
-		 "- Send CMD23 reliable write bit set\n"
-		 "- Send CMD23 bits [16-29] set\n"
-		 "- Send CMD23 header block not in block_count\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations send_invalid_packed_test_ops = {
-	.open = test_open,
-	.write = send_invalid_packed_test_write,
-	.read = send_invalid_packed_test_read,
-};
-
-/* packing_control TEST */
-static ssize_t write_packing_control_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-	int j = 0;
-	struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
-	int max_num_requests = mq->card->ext_csd.max_packed_writes;
-	int test_successful = 1;
-
-	test_pr_info("%s: -- write_packing_control TEST --", __func__);
-
-	sscanf(buf, "%d", &number);
-
-	if (number <= 0)
-		number = 1;
-
-	test_pr_info("%s: max_num_requests = %d ", __func__,
-			max_num_requests);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-	mbtd->test_group = TEST_PACKING_CONTROL_GROUP;
-
-	if (validate_packed_commands_settings())
-		return count;
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_test;
-	mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-
-	for (i = 0; i < number; ++i) {
-		test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
-		test_pr_info("%s: ====================", __func__);
-
-		for (j = PACKING_CONTROL_MIN_TESTCASE;
-				j <= PACKING_CONTROL_MAX_TESTCASE; j++) {
-
-			test_successful = 1;
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret) {
-				test_successful = 0;
-				break;
-			}
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-
-			mbtd->test_info.testcase = j;
-			mbtd->is_random = NON_RANDOM_TEST;
-			ret = test_iosched_start_test(&mbtd->test_info);
-			if (ret) {
-				test_successful = 0;
-				break;
-			}
-			/* Allow FS requests to be dispatched */
-			msleep(1000);
-		}
-
-		if (!test_successful)
-			break;
-	}
-
-	test_pr_info("%s: Completed all the test cases.", __func__);
-
-	return count;
-}
-
-static ssize_t write_packing_control_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nwrite_packing_control_test\n"
-		 "=========\n"
-		 "Description:\n"
-		 "This test checks the following scenarios\n"
-		 "- Packing expected - one over trigger\n"
-		 "- Packing expected - N over trigger\n"
-		 "- Packing expected - N over trigger followed by read\n"
-		 "- Packing expected - N over trigger followed by flush\n"
-		 "- Packing expected - threshold over trigger FB by flush\n"
-		 "- Packing not expected - less than trigger\n"
-		 "- Packing not expected - trigger requests\n"
-		 "- Packing not expected - trigger, read, trigger\n"
-		 "- Mixed state - packing -> no packing -> packing\n"
-		 "- Mixed state - no packing -> packing -> no packing\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations write_packing_control_test_ops = {
-	.open = test_open,
-	.write = write_packing_control_test_write,
-	.read = write_packing_control_test_read,
-};
-
-static ssize_t write_discard_sanitize_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	sscanf(buf, "%d", &number);
-	if (number <= 0)
-		number = 1;
-
-	test_pr_info("%s: -- write_discard_sanitize TEST --\n", __func__);
-
-	memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
-	mbtd->test_group = TEST_GENERAL_GROUP;
-
-	mbtd->test_info.data = mbtd;
-	mbtd->test_info.prepare_test_fn = prepare_write_discard_sanitize_read;
-	mbtd->test_info.get_test_case_str_fn = get_test_case_str;
-	mbtd->test_info.timeout_msec = SANITIZE_TEST_TIMEOUT;
-
-	for (i = 0 ; i < number ; ++i) {
-		test_pr_info("%s: Cycle # %d / %d\n", __func__, i+1, number);
-		test_pr_info("%s: ===================", __func__);
-
-		mbtd->test_info.testcase = TEST_WRITE_DISCARD_SANITIZE_READ;
-		ret = test_iosched_start_test(&mbtd->test_info);
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-const struct file_operations write_discard_sanitize_test_ops = {
-	.open = test_open,
-	.write = write_discard_sanitize_test_write,
-};
-
-static void mmc_block_test_debugfs_cleanup(void)
-{
-	debugfs_remove(mbtd->debug.random_test_seed);
-	debugfs_remove(mbtd->debug.send_write_packing_test);
-	debugfs_remove(mbtd->debug.err_check_test);
-	debugfs_remove(mbtd->debug.send_invalid_packed_test);
-	debugfs_remove(mbtd->debug.packing_control_test);
-	debugfs_remove(mbtd->debug.discard_sanitize_test);
-}
-
-static int mmc_block_test_debugfs_init(void)
-{
-	struct dentry *utils_root, *tests_root;
-
-	utils_root = test_iosched_get_debugfs_utils_root();
-	tests_root = test_iosched_get_debugfs_tests_root();
-
-	if (!utils_root || !tests_root)
-		return -EINVAL;
-
-	mbtd->debug.random_test_seed = debugfs_create_u32(
-					"random_test_seed",
-					S_IRUGO | S_IWUGO,
-					utils_root,
-					&mbtd->random_test_seed);
-
-	if (!mbtd->debug.random_test_seed)
-		goto err_nomem;
-
-	mbtd->debug.send_write_packing_test =
-		debugfs_create_file("send_write_packing_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &send_write_packing_test_ops);
-
-	if (!mbtd->debug.send_write_packing_test)
-		goto err_nomem;
-
-	mbtd->debug.err_check_test =
-		debugfs_create_file("err_check_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &err_check_test_ops);
-
-	if (!mbtd->debug.err_check_test)
-		goto err_nomem;
-
-	mbtd->debug.send_invalid_packed_test =
-		debugfs_create_file("send_invalid_packed_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &send_invalid_packed_test_ops);
-
-	if (!mbtd->debug.send_invalid_packed_test)
-		goto err_nomem;
-
-	mbtd->debug.packing_control_test = debugfs_create_file(
-					"packing_control_test",
-					S_IRUGO | S_IWUGO,
-					tests_root,
-					NULL,
-					&write_packing_control_test_ops);
-
-	if (!mbtd->debug.packing_control_test)
-		goto err_nomem;
-
-	mbtd->debug.discard_sanitize_test =
-		debugfs_create_file("write_discard_sanitize_test",
-				    S_IRUGO | S_IWUGO,
-				    tests_root,
-				    NULL,
-				    &write_discard_sanitize_test_ops);
-	if (!mbtd->debug.discard_sanitize_test) {
-		mmc_block_test_debugfs_cleanup();
-		return -ENOMEM;
-	}
-
-	return 0;
-
-err_nomem:
-	mmc_block_test_debugfs_cleanup();
-	return -ENOMEM;
-}
-
-static void mmc_block_test_probe(void)
-{
-	struct request_queue *q = test_iosched_get_req_queue();
-	struct mmc_queue *mq;
-	int max_packed_reqs;
-
-	if (!q) {
-		test_pr_err("%s: NULL request queue", __func__);
-		return;
-	}
-
-	mq = q->queuedata;
-	if (!mq) {
-		test_pr_err("%s: NULL mq", __func__);
-		return;
-	}
-
-	max_packed_reqs = mq->card->ext_csd.max_packed_writes;
-	mbtd->exp_packed_stats.packing_events =
-			kzalloc((max_packed_reqs + 1) *
-				sizeof(*mbtd->exp_packed_stats.packing_events),
-				GFP_KERNEL);
-
-	mmc_block_test_debugfs_init();
-}
-
-static void mmc_block_test_remove(void)
-{
-	mmc_block_test_debugfs_cleanup();
-}
-
-static int __init mmc_block_test_init(void)
-{
-	mbtd = kzalloc(sizeof(struct mmc_block_test_data), GFP_KERNEL);
-	if (!mbtd) {
-		test_pr_err("%s: failed to allocate mmc_block_test_data",
-			    __func__);
-		return -ENODEV;
-	}
-
-	mbtd->bdt.init_fn = mmc_block_test_probe;
-	mbtd->bdt.exit_fn = mmc_block_test_remove;
-	INIT_LIST_HEAD(&mbtd->bdt.list);
-	test_iosched_register(&mbtd->bdt);
-
-	return 0;
-}
-
-static void __exit mmc_block_test_exit(void)
-{
-	test_iosched_unregister(&mbtd->bdt);
-	kfree(mbtd);
-}
-
-module_init(mmc_block_test_init);
-module_exit(mmc_block_test_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MMC block test");
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e1e4408..d818fc4 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -25,13 +25,6 @@
 #define MMC_QUEUE_SUSPENDED	(1 << 0)
 
 /*
- * Based on benchmark tests the default num of requests to trigger the write
- * packing was determined, to keep the read latency as low as possible and
- * manage to keep the high write throughput.
- */
-#define DEFAULT_NUM_REQS_TO_START_PACK 17
-
-/*
  * Prepare a MMC request. This just filters out odd stuff.
  */
 static int mmc_prep_request(struct request_queue *q, struct request *req)
@@ -188,14 +181,14 @@
 	if (!mq->queue)
 		return -ENOMEM;
 
-	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
-	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
 	INIT_LIST_HEAD(&mqrq_cur->packed_list);
 	INIT_LIST_HEAD(&mqrq_prev->packed_list);
+
+	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
 	mq->mqrq_cur = mqrq_cur;
 	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
-	mq->num_wr_reqs_to_start_packing = DEFAULT_NUM_REQS_TO_START_PACK;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index ec3d6d2..5e04938 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -12,17 +12,6 @@
 	struct mmc_data		data;
 };
 
-enum mmc_blk_status {
-	MMC_BLK_SUCCESS = 0,
-	MMC_BLK_PARTIAL,
-	MMC_BLK_CMD_ERR,
-	MMC_BLK_RETRY,
-	MMC_BLK_ABORT,
-	MMC_BLK_DATA_ERR,
-	MMC_BLK_ECC_ERR,
-	MMC_BLK_NOMEDIUM,
-};
-
 enum mmc_packed_cmd {
 	MMC_PACKED_NONE = 0,
 	MMC_PACKED_WRITE,
@@ -40,6 +29,7 @@
 	u32			packed_cmd_hdr[128];
 	unsigned int		packed_blocks;
 	enum mmc_packed_cmd	packed_cmd;
+	int		packed_retries;
 	int		packed_fail_idx;
 	u8		packed_num;
 };
@@ -55,11 +45,6 @@
 	struct mmc_queue_req	mqrq[2];
 	struct mmc_queue_req	*mqrq_cur;
 	struct mmc_queue_req	*mqrq_prev;
-	bool			wr_packing_enabled;
-	int			num_of_potential_packed_wr_reqs;
-	int			num_wr_reqs_to_start_packing;
-	int (*err_check_fn) (struct mmc_card *, struct mmc_async_req *);
-	void (*packed_test_fn) (struct request_queue *, struct mmc_queue_req *);
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -73,6 +58,4 @@
 extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
 extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 
-extern void print_mmc_packing_stats(struct mmc_card *card);
-
 #endif
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 0592f9d..33f7d29 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -254,8 +254,6 @@
 	card->dev.release = mmc_release_card;
 	card->dev.type = type;
 
-	spin_lock_init(&card->wr_pack_stats.lock);
-
 	return card;
 }
 
@@ -358,8 +356,6 @@
 		device_del(&card->dev);
 	}
 
-	kfree(card->wr_pack_stats.packing_events);
-
 	put_device(&card->dev);
 }
 
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 898e358..9ab5b17 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -318,164 +318,6 @@
 	.llseek		= default_llseek,
 };
 
-static int mmc_wr_pack_stats_open(struct inode *inode, struct file *filp)
-{
-	struct mmc_card *card = inode->i_private;
-
-	filp->private_data = card;
-	card->wr_pack_stats.print_in_read = 1;
-	return 0;
-}
-
-#define TEMP_BUF_SIZE 256
-static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf,
-				size_t cnt, loff_t *ppos)
-{
-	struct mmc_card *card = filp->private_data;
-	struct mmc_wr_pack_stats *pack_stats;
-	int i;
-	int max_num_of_packed_reqs = 0;
-	char *temp_buf;
-
-	if (!card)
-		return cnt;
-
-	if (!card->wr_pack_stats.print_in_read)
-		return 0;
-
-	if (!card->wr_pack_stats.enabled) {
-		pr_info("%s: write packing statistics are disabled\n",
-			 mmc_hostname(card->host));
-		goto exit;
-	}
-
-	pack_stats = &card->wr_pack_stats;
-
-	if (!pack_stats->packing_events) {
-		pr_info("%s: NULL packing_events\n", mmc_hostname(card->host));
-		goto exit;
-	}
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL);
-	if (!temp_buf)
-		goto exit;
-
-	spin_lock(&pack_stats->lock);
-
-	snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n",
-		mmc_hostname(card->host));
-	strlcat(ubuf, temp_buf, cnt);
-
-	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
-		if (pack_stats->packing_events[i]) {
-			snprintf(temp_buf, TEMP_BUF_SIZE,
-				 "%s: Packed %d reqs - %d times\n",
-				mmc_hostname(card->host), i,
-				pack_stats->packing_events[i]);
-			strlcat(ubuf, temp_buf, cnt);
-		}
-	}
-
-	snprintf(temp_buf, TEMP_BUF_SIZE,
-		 "%s: stopped packing due to the following reasons:\n",
-		 mmc_hostname(card->host));
-	strlcat(ubuf, temp_buf, cnt);
-
-	if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: exceed max num of segments\n",
-			 mmc_hostname(card->host),
-			 pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: exceed max num of sectors\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[EXCEEDS_SECTORS]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: wrong data direction\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[WRONG_DATA_DIR]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: flush or discard\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: empty queue\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[EMPTY_QUEUE]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[REL_WRITE]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: rel write\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[REL_WRITE]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-	if (pack_stats->pack_stop_reason[THRESHOLD]) {
-		snprintf(temp_buf, TEMP_BUF_SIZE,
-			 "%s: %d times: Threshold\n",
-			mmc_hostname(card->host),
-			pack_stats->pack_stop_reason[THRESHOLD]);
-		strlcat(ubuf, temp_buf, cnt);
-	}
-
-	spin_unlock(&pack_stats->lock);
-
-	kfree(temp_buf);
-
-	pr_info("%s", ubuf);
-
-exit:
-	if (card->wr_pack_stats.print_in_read == 1) {
-		card->wr_pack_stats.print_in_read = 0;
-		return strnlen(ubuf, cnt);
-	}
-
-	return 0;
-}
-
-static ssize_t mmc_wr_pack_stats_write(struct file *filp,
-				       const char __user *ubuf, size_t cnt,
-				       loff_t *ppos)
-{
-	struct mmc_card *card = filp->private_data;
-	int value;
-
-	if (!card)
-		return cnt;
-
-	sscanf(ubuf, "%d", &value);
-	if (value) {
-		mmc_blk_init_packed_statistics(card);
-	} else {
-		spin_lock(&card->wr_pack_stats.lock);
-		card->wr_pack_stats.enabled = false;
-		spin_unlock(&card->wr_pack_stats.lock);
-	}
-
-	return cnt;
-}
-
-static const struct file_operations mmc_dbg_wr_pack_stats_fops = {
-	.open		= mmc_wr_pack_stats_open,
-	.read		= mmc_wr_pack_stats_read,
-	.write		= mmc_wr_pack_stats_write,
-};
-
 void mmc_add_card_debugfs(struct mmc_card *card)
 {
 	struct mmc_host	*host = card->host;
@@ -508,12 +350,6 @@
 					&mmc_dbg_ext_csd_fops))
 			goto err;
 
-	if (mmc_card_mmc(card) && (card->ext_csd.rev >= 6) &&
-	    (card->host->caps2 & MMC_CAP2_PACKED_WR))
-		if (!debugfs_create_file("wr_pack_stats", S_IRUSR, root, card,
-					 &mmc_dbg_wr_pack_stats_fops))
-			goto err;
-
 	return;
 
 err:
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6343760..e2172c5 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -469,6 +469,16 @@
 			card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
 			card->ext_csd.raw_bkops_status =
 				ext_csd[EXT_CSD_BKOPS_STATUS];
+			if (!card->ext_csd.bkops_en &&
+				card->host->caps2 & MMC_CAP2_INIT_BKOPS) {
+				err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_BKOPS_EN, 1, 0);
+				if (err)
+					pr_warn("%s: Enabling BKOPS failed\n",
+						mmc_hostname(card->host));
+				else
+					card->ext_csd.bkops_en = 1;
+			}
 			if (!card->ext_csd.bkops_en)
 				pr_info("%s: BKOPS_EN bit is not set\n",
 					mmc_hostname(card->host));
@@ -527,6 +537,7 @@
 		} else {
 			card->ext_csd.data_tag_unit_size = 0;
 		}
+
 		card->ext_csd.max_packed_writes =
 			ext_csd[EXT_CSD_MAX_PACKED_WRITES];
 		card->ext_csd.max_packed_reads =
@@ -1268,9 +1279,10 @@
 		}
 	}
 
-	if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
-			(card->ext_csd.max_packed_writes > 0) &&
-			(card->ext_csd.max_packed_reads > 0)) {
+	if ((host->caps2 & MMC_CAP2_PACKED_WR &&
+			card->ext_csd.max_packed_writes > 0) ||
+	    (host->caps2 & MMC_CAP2_PACKED_RD &&
+			card->ext_csd.max_packed_reads > 0)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_EXP_EVENTS_CTRL,
 				EXT_CSD_PACKED_EVENT_EN,
@@ -1285,24 +1297,6 @@
 		} else {
 			card->ext_csd.packed_event_en = 1;
 		}
-
-	}
-
-	if (!oldcard) {
-		if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
-		    (card->ext_csd.max_packed_writes > 0)) {
-			/*
-			 * We would like to keep the statistics in an index
-			 * that equals the num of packed requests
-			 * (1 to max_packed_writes)
-			 */
-			card->wr_pack_stats.packing_events = kzalloc(
-				(card->ext_csd.max_packed_writes + 1) *
-				sizeof(*card->wr_pack_stats.packing_events),
-				GFP_KERNEL);
-			if (!card->wr_pack_stats.packing_events)
-				goto free_card;
-		}
 	}
 
 	if (!oldcard)
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index c4b41e1..357d290 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -79,7 +79,6 @@
 #if defined(CONFIG_DEBUG_FS)
 static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
 static struct dentry *debugfs_dir;
-static struct dentry *debugfs_file;
 static int  msmsdcc_dbg_init(void);
 #endif
 
@@ -874,6 +873,10 @@
 	bool ret = true;
 	u32 xfer_size = data->blksz * data->blocks;
 
+	if (host->enforce_pio_mode) {
+		ret = false;
+		goto out;
+	}
 	if (is_sps_mode(host)) {
 		/*
 		 * BAM Mode: Fall back on PIO if size is less
@@ -892,7 +895,7 @@
 		/* PIO Mode */
 		ret = false;
 	}
-
+ out:
 	return ret;
 }
 
@@ -1776,6 +1779,7 @@
 msmsdcc_irq(int irq, void *dev_id)
 {
 	struct msmsdcc_host	*host = dev_id;
+	struct mmc_host		*mmc = host->mmc;
 	u32			status;
 	int			ret = 0;
 	int			timer = 0;
@@ -1817,6 +1821,12 @@
 				 */
 				wake_lock(&host->sdio_wlock);
 			} else {
+				if (!mmc->card || !mmc_card_sdio(mmc->card)) {
+					WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
+					     mmc_hostname(mmc));
+					ret = 1;
+					break;
+				}
 				spin_unlock(&host->lock);
 				mmc_signal_sdio_irq(host->mmc);
 				spin_lock(&host->lock);
@@ -1845,6 +1855,12 @@
 #endif
 
 		if (status & MCI_SDIOINTROPE) {
+			if (!mmc->card || mmc_card_sdio(mmc->card)) {
+				WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
+					mmc_hostname(mmc));
+				ret = 1;
+				break;
+			}
 			if (host->sdcc_suspending)
 				wake_lock(&host->sdio_suspend_wlock);
 			spin_unlock(&host->lock);
@@ -2394,7 +2410,8 @@
 
 	curr_slot = host->plat->vreg_data;
 	if (!curr_slot) {
-		rc = -EINVAL;
+		pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
+			 mmc_hostname(host->mmc));
 		goto out;
 	}
 
@@ -2822,6 +2839,14 @@
 		msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
 		msmsdcc_update_io_pad_pwr_switch(host);
 		msmsdcc_setup_pins(host, false);
+		/*
+		 * Reset the mask to prevent hitting any pending interrupts
+		 * after powering up the card again.
+		 */
+		if (atomic_read(&host->clks_on)) {
+			writel_relaxed(0, host->base + MMCIMASK0);
+			mb();
+		}
 		break;
 	case MMC_POWER_UP:
 		/* writing PWR_UP bit is redundant */
@@ -3463,7 +3488,6 @@
 {
 	struct device *dev = mmc->parent;
 	struct msmsdcc_host *host = mmc_priv(mmc);
-	unsigned long flags;
 	int rc = 0;
 
 	msmsdcc_pm_qos_update_latency(host, 1);
@@ -3497,7 +3521,6 @@
 static int msmsdcc_disable(struct mmc_host *mmc)
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
-	unsigned long flags;
 	int rc = 0;
 
 	msmsdcc_pm_qos_update_latency(host, 0);
@@ -4806,7 +4829,7 @@
 	struct msmsdcc_host *host = mmc_priv(mmc);
 
 	return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
-		host->idle_tout_ms / 1000);
+		host->idle_tout / 1000);
 }
 
 static ssize_t
@@ -4821,7 +4844,7 @@
 	if (!kstrtou32(buf, 0, &timeout)
 			&& (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
 		spin_lock_irqsave(&host->lock, flags);
-		host->idle_tout_ms = timeout * 1000;
+		host->idle_tout = timeout * 1000;
 		spin_unlock_irqrestore(&host->lock, flags);
 	}
 	return count;
@@ -5802,10 +5825,10 @@
 				MMC_CAP_SET_XPC_180);
 
 	mmc->caps2 |= MMC_CAP2_PACKED_WR;
-	mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
 	mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
 	mmc->caps2 |= MMC_CAP2_SANITIZE;
 	mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
+	mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
 
 	if (plat->nonremovable)
 		mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -5947,7 +5970,7 @@
 		pm_runtime_enable(&(pdev)->dev);
 	}
 #endif
-	host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
+	host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
 	setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
 			(unsigned long)host);
 
@@ -6126,6 +6149,16 @@
 	return ret;
 }
 
+#ifdef CONFIG_DEBUG_FS
+static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
+{
+	debugfs_remove_recursive(host->debugfs_host_dir);
+	host->debugfs_host_dir = NULL;
+}
+#else
+static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
+#endif
+
 static int msmsdcc_remove(struct platform_device *pdev)
 {
 	struct mmc_host *mmc = mmc_get_drvdata(pdev);
@@ -6152,6 +6185,8 @@
 		device_remove_file(&pdev->dev, &host->polling);
 	device_remove_file(&pdev->dev, &host->idle_timeout);
 
+	msmsdcc_remove_debugfs(host);
+
 	del_timer_sync(&host->req_tout_timer);
 	tasklet_kill(&host->dma_tlet);
 	tasklet_kill(&host->sps.tlet);
@@ -6328,6 +6363,23 @@
 }
 #endif
 
+#if CONFIG_DEBUG_FS
+static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
+		const char *func)
+{
+	ktime_t diff;
+
+	if (host->print_pm_stats) {
+		diff = ktime_sub(ktime_get(), start);
+		pr_info("%s: %s: Completed in %llu usec\n", func,
+		mmc_hostname(host->mmc), (u64)ktime_to_us(diff));
+	}
+}
+#else
+static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
+		const char *func) {}
+#endif
+
 static int
 msmsdcc_runtime_suspend(struct device *dev)
 {
@@ -6335,6 +6387,7 @@
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
 	unsigned long flags;
+	ktime_t start = ktime_get();
 
 	if (host->plat->is_sdio_al_client) {
 		rc = 0;
@@ -6391,6 +6444,7 @@
 out:
 	/* set bus bandwidth to 0 immediately */
 	msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return rc;
 }
 
@@ -6400,9 +6454,10 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long flags;
+	ktime_t start = ktime_get();
 
 	if (host->plat->is_sdio_al_client)
-		return 0;
+		goto out;
 
 	pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
 	if (mmc) {
@@ -6437,6 +6492,8 @@
 	}
 	host->pending_resume = false;
 	pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
+out:
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return 0;
 }
 
@@ -6449,7 +6506,7 @@
 		return 0;
 
 	/* Idle timeout is not configurable for now */
-	pm_schedule_suspend(dev, host->idle_tout_ms);
+	pm_schedule_suspend(dev, host->idle_tout);
 
 	return -EAGAIN;
 }
@@ -6459,17 +6516,19 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
+	ktime_t start = ktime_get();
 
-	if (host->plat->is_sdio_al_client)
-		return 0;
-
-
+	if (host->plat->is_sdio_al_client) {
+		rc = 0;
+		goto out;
+	}
 	if (host->plat->status_irq)
 		disable_irq(host->plat->status_irq);
 
 	if (!pm_runtime_suspended(dev))
 		rc = msmsdcc_runtime_suspend(dev);
-
+ out:
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return rc;
 }
 
@@ -6502,10 +6561,12 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	int rc = 0;
+	ktime_t start = ktime_get();
 
-	if (host->plat->is_sdio_al_client)
-		return 0;
-
+	if (host->plat->is_sdio_al_client) {
+		rc = 0;
+		goto out;
+	}
 	if (mmc->card && mmc_card_sdio(mmc->card))
 		rc = msmsdcc_runtime_resume(dev);
 	/*
@@ -6521,7 +6582,8 @@
 		msmsdcc_check_status((unsigned long)host);
 		enable_irq(host->plat->status_irq);
 	}
-
+out:
+	msmsdcc_print_pm_stats(host, start, __func__);
 	return rc;
 }
 
@@ -6595,7 +6657,6 @@
 	platform_driver_unregister(&msmsdcc_driver);
 
 #if defined(CONFIG_DEBUG_FS)
-	debugfs_remove(debugfs_file);
 	debugfs_remove(debugfs_dir);
 #endif
 }
@@ -6607,59 +6668,128 @@
 MODULE_LICENSE("GPL");
 
 #if defined(CONFIG_DEBUG_FS)
-
-static int
-msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
+static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
 {
-	file->private_data = inode->i_private;
+	struct msmsdcc_host *host = data;
+
+	*val = host->idle_tout / 1000L;
 	return 0;
 }
 
-static ssize_t
-msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
-		       size_t count, loff_t *ppos)
+static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
 {
-	struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
-	char buf[200];
-	int max, i;
+	struct msmsdcc_host *host = data;
+	unsigned long flags;
 
-	i = 0;
-	max = sizeof(buf) - 1;
+	spin_lock_irqsave(&host->lock, flags);
+	host->idle_tout = (u32)val * 1000;
+	spin_unlock_irqrestore(&host->lock, flags);
 
-	i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
-		       host->curr.cmd, host->curr.data);
-	if (host->curr.cmd) {
-		struct mmc_command *cmd = host->curr.cmd;
-
-		i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
-			      cmd->opcode, cmd->arg, cmd->flags);
-	}
-	if (host->curr.data) {
-		struct mmc_data *data = host->curr.data;
-		i += scnprintf(buf + i, max - i,
-			      "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
-			      data->timeout_ns, data->timeout_clks,
-			      data->blksz, data->blocks, data->error,
-			      data->flags);
-		i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
-			      host->curr.xfer_size, host->curr.xfer_remain,
-			      host->curr.data_xfered, host->dma.sg);
-	}
-
-	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+	return 0;
 }
 
-static const struct file_operations msmsdcc_dbg_state_ops = {
-	.read	= msmsdcc_dbg_state_read,
-	.open	= msmsdcc_dbg_state_open,
-};
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
+			msmsdcc_dbg_idle_tout_get,
+			msmsdcc_dbg_idle_tout_set,
+			"%llu\n");
+
+static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
+{
+	struct msmsdcc_host *host = data;
+
+	*val = (u64) host->enforce_pio_mode;
+	return 0;
+}
+
+static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
+{
+	struct msmsdcc_host *host = data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->enforce_pio_mode = !!val;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
+			msmsdcc_dbg_pio_mode_get,
+			msmsdcc_dbg_pio_mode_set,
+			"%llu\n");
+
+static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
+{
+	struct msmsdcc_host *host = data;
+
+	*val = !!host->print_pm_stats;
+	return 0;
+}
+
+static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
+{
+	struct msmsdcc_host *host = data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->print_pm_stats = !!val;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
+			msmsdcc_dbg_pm_stats_get,
+			msmsdcc_dbg_pm_stats_set,
+			"%llu\n");
 
 static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
 {
-	if (debugfs_dir) {
-		debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
-							0644, debugfs_dir, host,
-							&msmsdcc_dbg_state_ops);
+	int err = 0;
+
+	if (!debugfs_dir)
+		return;
+
+	host->debugfs_host_dir = debugfs_create_dir(
+			mmc_hostname(host->mmc), debugfs_dir);
+	if (IS_ERR(host->debugfs_host_dir)) {
+		err = PTR_ERR(host->debugfs_host_dir);
+		host->debugfs_host_dir = NULL;
+		pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
+			mmc_hostname(host->mmc), err);
+		return;
+	}
+
+	host->debugfs_idle_tout = debugfs_create_file("idle_tout",
+		S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+		&msmsdcc_dbg_idle_tout_ops);
+
+	if (IS_ERR(host->debugfs_idle_tout)) {
+		err = PTR_ERR(host->debugfs_idle_tout);
+		host->debugfs_idle_tout = NULL;
+		pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
+			mmc_hostname(host->mmc), err);
+	}
+
+	host->debugfs_pio_mode = debugfs_create_file("pio_mode",
+		S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+		&msmsdcc_dbg_pio_mode_ops);
+
+	if (IS_ERR(host->debugfs_pio_mode)) {
+		err = PTR_ERR(host->debugfs_pio_mode);
+		host->debugfs_pio_mode = NULL;
+		pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
+			mmc_hostname(host->mmc), err);
+	}
+
+	host->debugfs_pm_stats = debugfs_create_file("pm_stats",
+		S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+		&msmsdcc_dbg_pm_stats_ops);
+	if (IS_ERR(host->debugfs_pm_stats)) {
+		err = PTR_ERR(host->debugfs_pm_stats);
+		host->debugfs_pm_stats = NULL;
+		pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
+			mmc_hostname(host->mmc), err);
 	}
 }
 
@@ -6667,7 +6797,7 @@
 {
 	int err;
 
-	debugfs_dir = debugfs_create_dir("msmsdcc", 0);
+	debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
 	if (IS_ERR(debugfs_dir)) {
 		err = PTR_ERR(debugfs_dir);
 		debugfs_dir = NULL;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 5779491..c66d1a5 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -414,14 +414,20 @@
 	bool sdio_wakeupirq_disabled;
 	struct mutex clk_mutex;
 	bool pending_resume;
-	unsigned int idle_tout_ms;			/* Timeout in msecs */
+	unsigned int idle_tout;			/* Timeout in msecs */
 	bool pending_dpsm_reset;
+	bool enforce_pio_mode;
+	bool print_pm_stats;
 	struct msmsdcc_msm_bus_vote msm_bus_vote;
 	struct device_attribute	max_bus_bw;
 	struct device_attribute	polling;
 	struct device_attribute idle_timeout;
 	struct device_attribute auto_cmd19_attr;
 	struct device_attribute auto_cmd21_attr;
+	struct dentry *debugfs_host_dir;
+	struct dentry *debugfs_idle_tout;
+	struct dentry *debugfs_pio_mode;
+	struct dentry *debugfs_pm_stats;
 };
 
 #define MSMSDCC_VERSION_STEP_MASK	0x0000FFFF
@@ -483,7 +489,7 @@
 	if ((step == 0x18) && (minor >= 3))
 		host->hw_caps |= MSMSDCC_AUTO_CMD21;
 
-	if (version >= 0x2b) /* SDCC v4 2.1.0 and greater */
+	if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
 		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_AUTO_CMD21;
 }
 
diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c
index 61df241..41ad8af 100644
--- a/drivers/net/ethernet/msm/msm_rmnet.c
+++ b/drivers/net/ethernet/msm/msm_rmnet.c
@@ -501,16 +501,10 @@
 static int __rmnet_close(struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
-	int rc;
-	unsigned long flags;
 
-	if (p->ch) {
-		rc = smd_close(p->ch);
-		spin_lock_irqsave(&p->lock, flags);
-		p->ch = 0;
-		spin_unlock_irqrestore(&p->lock, flags);
-		return rc;
-	} else
+	if (p->ch)
+		return 0;
+	else
 		return -EBADF;
 }
 
@@ -529,12 +523,9 @@
 
 static int rmnet_stop(struct net_device *dev)
 {
-	struct rmnet_private *p = netdev_priv(dev);
-
 	DBG0("[%s] rmnet_stop()\n", dev->name);
 
 	netif_stop_queue(dev);
-	tasklet_kill(&p->tsklt);
 
 	/* TODO: unload modem safely,
 	   currently, this causes unnecessary unloads */
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index fbb3489..5f29406 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -79,6 +79,7 @@
 	unsigned long timeout_us;
 #endif
 	spinlock_t lock;
+	spinlock_t tx_queue_lock;
 	struct tasklet_struct tsklt;
 	/* IOCTL specified mode (protocol, QoS header) */
 	u32 operation_mode;
@@ -346,12 +347,15 @@
 		 ((struct net_device *)(dev))->name, p->stats.tx_packets,
 		 skb->len, skb->mark);
 	dev_kfree_skb_any(skb);
+
+	spin_lock_irqsave(&p->tx_queue_lock, flags);
 	if (netif_queue_stopped(dev) &&
 		msm_smux_is_ch_low(p->ch_id)) {
 		DBG0("%s: Low WM hit, waking queue=%p\n",
 			 __func__, skb);
 		netif_wake_queue(dev);
 	}
+	spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 }
 
 void rmnet_smux_notify(void *priv, int event_type, const void *metadata)
@@ -475,14 +479,20 @@
 
 	case SMUX_LOW_WM_HIT:
 		dev = priv;
+		p = netdev_priv(priv);
 		DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+		spin_lock_irqsave(&p->tx_queue_lock, flags);
 		netif_start_queue(dev);
+		spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 		break;
 
 	case SMUX_HIGH_WM_HIT:
 		dev = priv;
-		DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+		p = netdev_priv(priv);
+		DBG0("[%s] High WM hit dev:%s\n", __func__, dev->name);
+		spin_lock_irqsave(&p->tx_queue_lock, flags);
 		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 		break;
 
 	default:
@@ -573,7 +583,6 @@
 static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
-	int smux_ret;
 	struct QMI_QOS_HDR_S *qmih;
 	u32 opmode;
 	unsigned long flags;
@@ -593,21 +602,13 @@
 
 	dev->trans_start = jiffies;
 
-	/* if write() succeeds, skb access is unsafe in this process */
-	smux_ret = msm_smux_write(p->ch_id, skb, skb->data, skb->len);
-
-	if (smux_ret != 0 && smux_ret != -EAGAIN) {
-		pr_err("[%s] %s: write returned error %d",
-			   dev->name, __func__, smux_ret);
-		return -EPERM;
-	}
-
-	return smux_ret;
+	return msm_smux_write(p->ch_id, skb, skb->data, skb->len);
 }
 
 static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
+	unsigned long flags;
 	int ret = 0;
 
 	if (netif_queue_stopped(dev) || (p->device_state == DEVICE_INACTIVE)) {
@@ -616,17 +617,10 @@
 		return 0;
 	}
 
+	spin_lock_irqsave(&p->tx_queue_lock, flags);
 	ret = _rmnet_xmit(skb, dev);
 
-	if (ret == -EPERM) {
-		/* Do not stop the queue here.
-		 * It will lead to ir-recoverable state.
-		 */
-		ret = NETDEV_TX_BUSY;
-		goto exit;
-	}
-
-	if (msm_smux_is_ch_full(p->ch_id) || (ret == -EAGAIN)) {
+	if (ret == -EAGAIN) {
 		/*
 		 * EAGAIN means we attempted to overflow the high watermark
 		 * Clearly the queue is not stopped like it should be, so
@@ -636,9 +630,9 @@
 		 */
 		netif_stop_queue(dev);
 		ret = NETDEV_TX_BUSY;
-		goto exit;
 	}
-exit:
+	spin_unlock_irqrestore(&p->tx_queue_lock, flags);
+
 	return ret;
 }
 
@@ -892,6 +886,7 @@
 		p->ch_id = n;
 		p->in_reset = 0;
 		spin_lock_init(&p->lock);
+		spin_lock_init(&p->tx_queue_lock);
 #ifdef CONFIG_MSM_RMNET_DEBUG
 		p->timeout_us = timeout_us;
 		p->wakeups_xmit = p->wakeups_rcv = 0;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 1867fe2..6de0a77 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1529,6 +1529,7 @@
 		spin_lock_irq(&dev->txq.lock);
 		/* don't autosuspend while transmitting */
 		if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
+			dev->suspend_count--;
 			spin_unlock_irq(&dev->txq.lock);
 			return -EBUSY;
 		} else {
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index ac0a2fd..2bf857c 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -27,6 +27,7 @@
 #include <linux/of_gpio.h>
 #include <mach/peripheral-loader.h>
 #include <mach/msm_smd.h>
+#include <mach/msm_iomap.h>
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 #include "wcnss_prealloc.h"
 #endif
@@ -159,6 +160,18 @@
 static DEVICE_ATTR(wcnss_version, S_IRUSR,
 		wcnss_version_show, NULL);
 
+/* interface to reset Riva by sending the reset interrupt */
+void wcnss_reset_intr(void)
+{
+	if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
+		wmb();
+		__raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
+	} else {
+		pr_err("%s: reset interrupt not supported\n", __func__);
+	}
+}
+EXPORT_SYMBOL(wcnss_reset_intr);
+
 static int wcnss_create_sysfs(struct device *dev)
 {
 	int ret;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 33b12ae..76a758b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -39,8 +39,10 @@
 
 #define QPNP_PON_RESIN_PULL_UP		BIT(0)
 #define QPNP_PON_KPDPWR_PULL_UP		BIT(1)
+#define QPNP_PON_CBLPWR_PULL_UP		BIT(2)
 #define QPNP_PON_S2_CNTL_EN		BIT(7)
 #define QPNP_PON_S2_RESET_ENABLE	BIT(7)
+#define QPNP_PON_DELAY_BIT_SHIFT	6
 
 #define QPNP_PON_S1_TIMER_MASK		(0xF)
 #define QPNP_PON_S2_TIMER_MASK		(0x7)
@@ -49,6 +51,7 @@
 #define QPNP_PON_DBC_DELAY_MASK		(0x7)
 #define QPNP_PON_KPDPWR_N_SET		BIT(0)
 #define QPNP_PON_RESIN_N_SET		BIT(1)
+#define QPNP_PON_CBLPWR_N_SET		BIT(2)
 #define QPNP_PON_RESIN_BARK_N_SET	BIT(4)
 
 #define QPNP_PON_RESET_EN		BIT(7)
@@ -66,6 +69,7 @@
 enum pon_type {
 	PON_KPDPWR,
 	PON_RESIN,
+	PON_CBLPWR,
 };
 
 struct qpnp_pon_config {
@@ -214,6 +218,9 @@
 	case PON_RESIN:
 		pon_rt_bit = QPNP_PON_RESIN_N_SET;
 		break;
+	case PON_CBLPWR:
+		pon_rt_bit = QPNP_PON_CBLPWR_N_SET;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -253,6 +260,18 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t qpnp_cblpwr_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = qpnp_pon_input_dispatch(pon, PON_CBLPWR);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
+	return IRQ_HANDLED;
+}
+
 static void bark_work_func(struct work_struct *work)
 {
 	int rc;
@@ -351,6 +370,9 @@
 	case PON_RESIN:
 		pull_bit = QPNP_PON_RESIN_PULL_UP;
 		break;
+	case PON_CBLPWR:
+		pull_bit = QPNP_PON_CBLPWR_PULL_UP;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -489,6 +511,17 @@
 			}
 		}
 		break;
+	case PON_CBLPWR:
+		rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+							qpnp_cblpwr_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+					"qpnp_cblpwr_status", pon);
+		if (rc < 0) {
+			dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+							cfg->state_irq);
+			return rc;
+		}
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -595,6 +628,15 @@
 				}
 			}
 			break;
+		case PON_CBLPWR:
+			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "cblpwr");
+			if (cfg->state_irq < 0) {
+				dev_err(&pon->spmi->dev,
+						"Unable to get cblpwr irq\n");
+				return rc;
+			}
+			break;
 		default:
 			dev_err(&pon->spmi->dev, "PON RESET %d not supported",
 								cfg->pon_type);
@@ -763,11 +805,13 @@
 
 	rc = of_property_read_u32(pon->spmi->dev.of_node,
 				"qcom,pon-dbc-delay", &delay);
-	if (rc && rc != -EINVAL) {
-		dev_err(&spmi->dev, "Unable to read debounce delay\n");
-		return rc;
+	if (rc) {
+		if (rc != -EINVAL) {
+			dev_err(&spmi->dev, "Unable to read debounce delay\n");
+			return rc;
+		}
 	} else {
-		delay = (delay << 6) / USEC_PER_SEC;
+		delay = (delay << QPNP_PON_DELAY_BIT_SHIFT) / USEC_PER_SEC;
 		delay = ilog2(delay);
 		rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
 						QPNP_PON_DBC_DELAY_MASK, delay);
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 551c0a7..bf78b1c 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -258,6 +258,11 @@
 	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
 	int ret;
 
+	if (!usb_bam_pdev) {
+		pr_err("%s: usb_bam device not found\n", __func__);
+		return -ENODEV;
+	}
+
 	if (idx >= CONNECTIONS_NUM) {
 		pr_err("%s: Invalid connection index\n",
 			__func__);
@@ -715,12 +720,9 @@
 usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
 		    char *buf)
 {
-	struct platform_device *pdev =
-		container_of(dev, struct platform_device, dev);
-	struct msm_usb_bam_platform_data *pdata =
-		usb_bam_pdev->dev.platform_data;
+	struct msm_usb_bam_platform_data *pdata = dev->platform_data;
 
-	if (!pdev || !pdata)
+	if (!pdata)
 		return 0;
 	return scnprintf(buf, PAGE_SIZE, "%s\n",
 			 bam_enable_strings[pdata->usb_active_bam]);
@@ -730,13 +732,15 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t count)
 {
-	struct platform_device *pdev = container_of(dev,
-		struct platform_device, dev);
-	struct msm_usb_bam_platform_data *pdata =
-		usb_bam_pdev->dev.platform_data;
+	struct msm_usb_bam_platform_data *pdata = dev->platform_data;
 	char str[10], *pstr;
 	int ret, i;
 
+	if (!pdata) {
+		dev_err(dev, "no usb_bam pdata found\n");
+		return -ENODEV;
+	}
+
 	strlcpy(str, buf, sizeof(str));
 	pstr = strim(str);
 
@@ -745,12 +749,12 @@
 			pdata->usb_active_bam = i;
 	}
 
-	dev_dbg(&pdev->dev, "active_bam=%s\n",
+	dev_dbg(dev, "active_bam=%s\n",
 		bam_enable_strings[pdata->usb_active_bam]);
 
 	ret = usb_bam_init();
 	if (ret) {
-		dev_err(&pdev->dev, "failed to initialize usb bam\n");
+		dev_err(dev, "failed to initialize usb bam\n");
 		return ret;
 	}
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index c63c99f..e6e2f30 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  *
  */
-#define pr_fmt(fmt)	"%s: " fmt, __func__
 
+#define pr_fmt(fmt)	"%s: " fmt, __func__
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
@@ -22,6 +22,7 @@
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
@@ -147,8 +148,9 @@
 	int			ibat_at_cv_ua;
 	int			soc_at_cv;
 	int			prev_chg_soc;
-
 	struct power_supply	*batt_psy;
+	bool			low_voltage_wake_lock_held;
+	struct wake_lock	low_voltage_wake_lock;
 };
 
 /*
@@ -224,7 +226,6 @@
 module_param_cb(bms_end_ocv_uv, &bms_ro_param_ops, &bms_end_ocv_uv, 0644);
 module_param_cb(bms_end_cc_uah, &bms_ro_param_ops, &bms_end_cc_uah, 0644);
 
-static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp);
 static void readjust_fcc_table(void)
 {
 	struct single_row_lut *temp, *old;
@@ -241,7 +242,7 @@
 		return;
 	}
 
-	fcc = interpolate_fcc(the_chip, last_real_fcc_batt_temp);
+	fcc = interpolate_fcc(the_chip->fcc_temp_lut, last_real_fcc_batt_temp);
 
 	temp->cols = the_chip->fcc_temp_lut->cols;
 	for (i = 0; i < the_chip->fcc_temp_lut->cols; i++) {
@@ -583,342 +584,6 @@
 	return 0;
 }
 
-static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
-{
-	if (y0 == y1 || x == x0)
-		return y0;
-	if (x1 == x0 || x == x1)
-		return y1;
-
-	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
-}
-
-static int interpolate_single_lut(struct single_row_lut *lut, int x)
-{
-	int i, result;
-
-	if (x < lut->x[0]) {
-		pr_debug("x %d less than known range return y = %d lut = %pS\n",
-							x, lut->y[0], lut);
-		return lut->y[0];
-	}
-	if (x > lut->x[lut->cols - 1]) {
-		pr_debug("x %d more than known range return y = %d lut = %pS\n",
-						x, lut->y[lut->cols - 1], lut);
-		return lut->y[lut->cols - 1];
-	}
-
-	for (i = 0; i < lut->cols; i++)
-		if (x <= lut->x[i])
-			break;
-	if (x == lut->x[i]) {
-		result = lut->y[i];
-	} else {
-		result = linear_interpolate(
-			lut->y[i - 1],
-			lut->x[i - 1],
-			lut->y[i],
-			lut->x[i],
-			x);
-	}
-	return result;
-}
-
-static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp)
-{
-	/* batt_temp is in tenths of degC - convert it to degC for lookups */
-	batt_temp = batt_temp/10;
-	return interpolate_single_lut(chip->fcc_temp_lut, batt_temp);
-}
-
-static int interpolate_fcc_adjusted(struct pm8921_bms_chip *chip, int batt_temp)
-{
-	/* batt_temp is in tenths of degC - convert it to degC for lookups */
-	batt_temp = batt_temp/10;
-	return interpolate_single_lut(chip->adjusted_fcc_temp_lut, batt_temp);
-}
-
-static int interpolate_scalingfactor_fcc(struct pm8921_bms_chip *chip,
-								int cycles)
-{
-	/*
-	 * sf table could be null when no battery aging data is available, in
-	 * that case return 100%
-	 */
-	if (chip->fcc_sf_lut)
-		return interpolate_single_lut(chip->fcc_sf_lut, cycles);
-	else
-		return 100;
-}
-
-static int interpolate_scalingfactor(struct pm8921_bms_chip *chip,
-				struct sf_lut *sf_lut,
-				int row_entry, int pc)
-{
-	int i, scalefactorrow1, scalefactorrow2, scalefactor;
-	int rows, cols;
-	int row1 = 0;
-	int row2 = 0;
-
-	/*
-	 * sf table could be null when no battery aging data is available, in
-	 * that case return 100%
-	 */
-	if (!sf_lut)
-		return 100;
-
-	rows = sf_lut->rows;
-	cols = sf_lut->cols;
-	if (pc > sf_lut->percent[0]) {
-		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
-		row1 = 0;
-		row2 = 0;
-	}
-	if (pc < sf_lut->percent[rows - 1]) {
-		pr_debug("pc %d less than known pc ranges for sf", pc);
-		row1 = rows - 1;
-		row2 = rows - 1;
-	}
-	for (i = 0; i < rows; i++) {
-		if (pc == sf_lut->percent[i]) {
-			row1 = i;
-			row2 = i;
-			break;
-		}
-		if (pc > sf_lut->percent[i]) {
-			row1 = i - 1;
-			row2 = i;
-			break;
-		}
-	}
-
-	if (row_entry < sf_lut->row_entries[0])
-		row_entry = sf_lut->row_entries[0];
-	if (row_entry > sf_lut->row_entries[cols - 1])
-		row_entry = sf_lut->row_entries[cols - 1];
-
-	for (i = 0; i < cols; i++)
-		if (row_entry <= sf_lut->row_entries[i])
-			break;
-	if (row_entry == sf_lut->row_entries[i]) {
-		scalefactor = linear_interpolate(
-				sf_lut->sf[row1][i],
-				sf_lut->percent[row1],
-				sf_lut->sf[row2][i],
-				sf_lut->percent[row2],
-				pc);
-		return scalefactor;
-	}
-
-	scalefactorrow1 = linear_interpolate(
-				sf_lut->sf[row1][i - 1],
-				sf_lut->row_entries[i - 1],
-				sf_lut->sf[row1][i],
-				sf_lut->row_entries[i],
-				row_entry);
-
-	scalefactorrow2 = linear_interpolate(
-				sf_lut->sf[row2][i - 1],
-				sf_lut->row_entries[i - 1],
-				sf_lut->sf[row2][i],
-				sf_lut->row_entries[i],
-				row_entry);
-
-	scalefactor = linear_interpolate(
-				scalefactorrow1,
-				sf_lut->percent[row1],
-				scalefactorrow2,
-				sf_lut->percent[row2],
-				pc);
-
-	return scalefactor;
-}
-
-static int is_between(int left, int right, int value)
-{
-	if (left >= right && left >= value && value >= right)
-		return 1;
-	if (left <= right && left <= value && value <= right)
-		return 1;
-
-	return 0;
-}
-
-/* get ocv given a soc  -- reverse lookup */
-static int interpolate_ocv(struct pm8921_bms_chip *chip,
-				int batt_temp_degc, int pc)
-{
-	int i, ocvrow1, ocvrow2, ocv;
-	int rows, cols;
-	int row1 = 0;
-	int row2 = 0;
-
-	rows = chip->pc_temp_ocv_lut->rows;
-	cols = chip->pc_temp_ocv_lut->cols;
-	if (pc > chip->pc_temp_ocv_lut->percent[0]) {
-		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
-		row1 = 0;
-		row2 = 0;
-	}
-	if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
-		pr_debug("pc %d less than known pc ranges for sf\n", pc);
-		row1 = rows - 1;
-		row2 = rows - 1;
-	}
-	for (i = 0; i < rows; i++) {
-		if (pc == chip->pc_temp_ocv_lut->percent[i]) {
-			row1 = i;
-			row2 = i;
-			break;
-		}
-		if (pc > chip->pc_temp_ocv_lut->percent[i]) {
-			row1 = i - 1;
-			row2 = i;
-			break;
-		}
-	}
-
-	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
-	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
-
-	for (i = 0; i < cols; i++)
-		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
-			break;
-	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
-		ocv = linear_interpolate(
-				chip->pc_temp_ocv_lut->ocv[row1][i],
-				chip->pc_temp_ocv_lut->percent[row1],
-				chip->pc_temp_ocv_lut->ocv[row2][i],
-				chip->pc_temp_ocv_lut->percent[row2],
-				pc);
-		return ocv;
-	}
-
-	ocvrow1 = linear_interpolate(
-				chip->pc_temp_ocv_lut->ocv[row1][i - 1],
-				chip->pc_temp_ocv_lut->temp[i - 1],
-				chip->pc_temp_ocv_lut->ocv[row1][i],
-				chip->pc_temp_ocv_lut->temp[i],
-				batt_temp_degc);
-
-	ocvrow2 = linear_interpolate(
-				chip->pc_temp_ocv_lut->ocv[row2][i - 1],
-				chip->pc_temp_ocv_lut->temp[i - 1],
-				chip->pc_temp_ocv_lut->ocv[row2][i],
-				chip->pc_temp_ocv_lut->temp[i],
-				batt_temp_degc);
-
-	ocv = linear_interpolate(
-				ocvrow1,
-				chip->pc_temp_ocv_lut->percent[row1],
-				ocvrow2,
-				chip->pc_temp_ocv_lut->percent[row2],
-				pc);
-
-	return ocv;
-}
-
-static int interpolate_pc(struct pm8921_bms_chip *chip,
-				int batt_temp_degc, int ocv)
-{
-	int i, j, pcj, pcj_minus_one, pc;
-	int rows = chip->pc_temp_ocv_lut->rows;
-	int cols = chip->pc_temp_ocv_lut->cols;
-
-
-	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0]) {
-		pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
-	}
-	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1]) {
-		pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
-		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
-	}
-
-	for (j = 0; j < cols; j++)
-		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[j])
-			break;
-	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[j]) {
-		/* found an exact match for temp in the table */
-		if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
-			return chip->pc_temp_ocv_lut->percent[0];
-		if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j])
-			return chip->pc_temp_ocv_lut->percent[rows - 1];
-		for (i = 0; i < rows; i++) {
-			if (ocv >= chip->pc_temp_ocv_lut->ocv[i][j]) {
-				if (ocv == chip->pc_temp_ocv_lut->ocv[i][j])
-					return
-					chip->pc_temp_ocv_lut->percent[i];
-				pc = linear_interpolate(
-					chip->pc_temp_ocv_lut->percent[i],
-					chip->pc_temp_ocv_lut->ocv[i][j],
-					chip->pc_temp_ocv_lut->percent[i - 1],
-					chip->pc_temp_ocv_lut->ocv[i - 1][j],
-					ocv);
-				return pc;
-			}
-		}
-	}
-
-	/*
-	 * batt_temp_degc is within temperature for
-	 * column j-1 and j
-	 */
-	if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
-		return chip->pc_temp_ocv_lut->percent[0];
-	if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j - 1])
-		return chip->pc_temp_ocv_lut->percent[rows - 1];
-
-	pcj_minus_one = 0;
-	pcj = 0;
-	for (i = 0; i < rows-1; i++) {
-		if (pcj == 0
-			&& is_between(chip->pc_temp_ocv_lut->ocv[i][j],
-				chip->pc_temp_ocv_lut->ocv[i+1][j], ocv)) {
-			pcj = linear_interpolate(
-				chip->pc_temp_ocv_lut->percent[i],
-				chip->pc_temp_ocv_lut->ocv[i][j],
-				chip->pc_temp_ocv_lut->percent[i + 1],
-				chip->pc_temp_ocv_lut->ocv[i+1][j],
-				ocv);
-		}
-
-		if (pcj_minus_one == 0
-			&& is_between(chip->pc_temp_ocv_lut->ocv[i][j-1],
-				chip->pc_temp_ocv_lut->ocv[i+1][j-1], ocv)) {
-
-			pcj_minus_one = linear_interpolate(
-				chip->pc_temp_ocv_lut->percent[i],
-				chip->pc_temp_ocv_lut->ocv[i][j-1],
-				chip->pc_temp_ocv_lut->percent[i + 1],
-				chip->pc_temp_ocv_lut->ocv[i+1][j-1],
-				ocv);
-		}
-
-		if (pcj && pcj_minus_one) {
-			pc = linear_interpolate(
-				pcj_minus_one,
-				chip->pc_temp_ocv_lut->temp[j-1],
-				pcj,
-				chip->pc_temp_ocv_lut->temp[j],
-				batt_temp_degc);
-			return pc;
-		}
-	}
-
-	if (pcj)
-		return pcj;
-
-	if (pcj_minus_one)
-		return pcj_minus_one;
-
-	pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
-							ocv, batt_temp_degc);
-	return 100;
-}
-
 #define BMS_MODE_BIT	BIT(6)
 #define EN_VBAT_BIT	BIT(5)
 #define OVERRIDE_MODE_DELAY_MS	20
@@ -1042,7 +707,7 @@
 	}
 	/* Convert the batt_temp to DegC from deciDegC */
 	batt_temp = batt_temp / 10;
-	scalefactor = interpolate_scalingfactor(chip, chip->rbatt_sf_lut,
+	scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
 							batt_temp, soc_rbatt);
 	pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
 				scalefactor, batt_temp, soc_rbatt);
@@ -1069,16 +734,18 @@
 	int initfcc, result, scalefactor = 0;
 
 	if (chip->adjusted_fcc_temp_lut == NULL) {
-		initfcc = interpolate_fcc(chip, batt_temp);
+		initfcc = interpolate_fcc(chip->fcc_temp_lut, batt_temp);
 
-		scalefactor = interpolate_scalingfactor_fcc(chip, chargecycles);
+		scalefactor = interpolate_scalingfactor_fcc(chip->fcc_sf_lut,
+				chargecycles);
 
 		/* Multiply the initial FCC value by the scale factor. */
 		result = (initfcc * scalefactor * 1000) / 100;
 		pr_debug("fcc = %d uAh\n", result);
 		return result;
 	} else {
-		return 1000 * interpolate_fcc_adjusted(chip, batt_temp);
+		return 1000 * interpolate_fcc(chip->adjusted_fcc_temp_lut,
+				batt_temp);
 	}
 }
 
@@ -1120,17 +787,18 @@
 	return 0;
 }
 
-static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
-							int chargecycles)
+static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv,
+					int batt_temp, int chargecycles)
 {
 	int pc, scalefactor;
 
-	pc = interpolate_pc(chip, batt_temp / 10, ocv_uv / 1000);
+	pc = interpolate_pc(chip->pc_temp_ocv_lut,
+			batt_temp / 10, ocv_uv / 1000);
 	pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
 					pc, ocv_uv, batt_temp);
 
-	scalefactor = interpolate_scalingfactor(chip,
-					chip->pc_sf_lut, chargecycles, pc);
+	scalefactor = interpolate_scalingfactor(chip->pc_sf_lut,
+			chargecycles, pc);
 	pr_debug("scalefactor = %u batt_temp = %d\n", scalefactor, batt_temp);
 
 	/* Multiply the initial FCC value by the scale factor. */
@@ -1183,7 +851,8 @@
 	int uuc_rbatt_uv;
 
 	for (i = 0; i <= 100; i++) {
-		ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+		ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+				batt_temp_degc, i);
 		rbatt_mohm = get_rbatt(chip, i, batt_temp);
 		unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
 		delta_uv = ocv_mv * 1000 - unusable_uv;
@@ -1239,8 +908,8 @@
 	new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
 
 	/* also find update the iavg_ma accordingly */
-	new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
-						chip->prev_pc_unusable);
+	new_unusable_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+			batt_temp_degc, chip->prev_pc_unusable);
 	if (new_unusable_mv < chip->v_cutoff)
 		new_unusable_mv = chip->v_cutoff;
 
@@ -1531,11 +1200,11 @@
 	pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
 	pc = clamp(pc, 0, 100);
 
-	ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+	ocv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
 
 	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
 			shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
-	new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
 	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
 
 	while (abs(new_pc - pc) > 1) {
@@ -1545,7 +1214,8 @@
 			delta_mv = -1 * delta_mv;
 
 		ocv = ocv + delta_mv;
-		new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+		new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+				batt_temp_degc, ocv);
 		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
 	}
 
@@ -1650,6 +1320,28 @@
 	return chip->prev_chg_soc;
 }
 
+static void very_low_voltage_check(struct pm8921_bms_chip *chip,
+					int ibat_ua, int vbat_uv)
+{
+	/*
+	 * if battery is very low (v_cutoff voltage + 20mv) hold
+	 * a wakelock untill soc = 0%
+	 */
+	if (vbat_uv <= (chip->v_cutoff + 20) * 1000
+			&& !chip->low_voltage_wake_lock_held) {
+		pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
+		wake_lock(&chip->low_voltage_wake_lock);
+		chip->low_voltage_wake_lock_held = 1;
+	}
+
+	if (vbat_uv > (chip->v_cutoff + 20) * 1000
+			&& chip->low_voltage_wake_lock_held) {
+		pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
+		chip->low_voltage_wake_lock_held = 0;
+		wake_unlock(&chip->low_voltage_wake_lock);
+	}
+}
+
 static int last_soc_est = -EINVAL;
 static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
 		int batt_temp, int chargecycles,
@@ -1674,6 +1366,7 @@
 		goto out;
 	}
 
+	very_low_voltage_check(chip, ibat_ua, vbat_uv);
 
 	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
 
@@ -3228,6 +2921,9 @@
 		goto free_chip;
 	}
 
+	wake_lock_init(&chip->low_voltage_wake_lock,
+			WAKE_LOCK_SUSPEND, "pm8921_bms_low");
+
 	rc = pm8921_bms_hw_init(chip);
 	if (rc) {
 		pr_err("couldn't init hardware rc = %d\n", rc);
@@ -3285,12 +2981,33 @@
 	return 0;
 }
 
+static int pm8921_bms_resume(struct device *dev)
+{
+	int rc, ibat_ua, vbat_uv;
+
+	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+							&ibat_ua,
+							&vbat_uv);
+	if (rc < 0) {
+		pr_err("simultaneous vbat ibat failed err = %d\n", rc);
+		return 0;
+	}
+
+	very_low_voltage_check(the_chip, ibat_ua, vbat_uv);
+	return 0;
+}
+
+static const struct dev_pm_ops pm8921_bms_pm_ops = {
+	.resume		= pm8921_bms_resume,
+};
+
 static struct platform_driver pm8921_bms_driver = {
 	.probe	= pm8921_bms_probe,
 	.remove	= __devexit_p(pm8921_bms_remove),
 	.driver	= {
 		.name	= PM8921_BMS_DEV_NAME,
 		.owner	= THIS_MODULE,
+		.pm	= &pm8921_bms_pm_ops,
 	},
 };
 
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e4e0004..19454ca 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -27,6 +27,7 @@
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/mfd/pm8xxx/batt-alarm.h>
 
 #include <mach/msm_xo.h>
 #include <mach/msm_hsusb.h>
@@ -115,6 +116,13 @@
 	int			batt_state;
 };
 
+static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
+					  unsigned long status, void *unused);
+
+static struct notifier_block alarm_notifier = {
+	.notifier_call = pm8921_battery_gauge_alarm_notify,
+};
+
 static struct fsm_state_to_batt_status map[] = {
 	{FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
 	{FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
@@ -205,6 +213,8 @@
  * @max_voltage_mv:		the max volts the batt should be charged up to
  * @min_voltage_mv:		the min battery voltage before turning the FETon
  * @uvd_voltage_mv:		(PM8917 only) the falling UVD threshold voltage
+ * @alarm_low_mv:		the battery alarm voltage low
+ * @alarm_high_mv:		the battery alarm voltage high
  * @cool_temp_dc:		the cool temp threshold in deciCelcius
  * @warm_temp_dc:		the warm temp threshold in deciCelcius
  * @resume_voltage_delta:	the voltage delta from vdd max at which the
@@ -225,6 +235,8 @@
 	unsigned int			max_voltage_mv;
 	unsigned int			min_voltage_mv;
 	unsigned int			uvd_voltage_mv;
+	unsigned int			alarm_low_mv;
+	unsigned int			alarm_high_mv;
 	int				cool_temp_dc;
 	int				warm_temp_dc;
 	unsigned int			temp_check_period;
@@ -250,6 +262,7 @@
 	bool				ext_charge_done;
 	bool				iusb_fine_res;
 	bool				dc_unplug_check;
+	bool				disable_hw_clock_switching;
 	DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
 	struct work_struct		battery_id_valid_work;
 	int64_t				batt_id_min;
@@ -2003,6 +2016,73 @@
 	return get_prop_batt_temp(the_chip);
 }
 
+static int pm8921_charger_enable_batt_alarm(struct pm8921_chg_chip *chip)
+{
+	int rc = 0;
+
+	rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+	if (!rc)
+		rc = pm8xxx_batt_alarm_enable(
+			PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+	if (rc) {
+		pr_err("unable to set batt alarm state rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+static int pm8921_charger_configure_batt_alarm(struct pm8921_chg_chip *chip)
+{
+	int rc = 0;
+
+	rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+	if (!rc)
+		rc = pm8xxx_batt_alarm_disable(
+			PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+	if (rc) {
+		pr_err("unable to set batt alarm state rc=%d\n", rc);
+		return rc;
+	}
+
+	/*
+	 * The batt-alarm driver requires sane values for both min / max,
+	 * regardless of whether they're both activated.
+	 */
+	rc = pm8xxx_batt_alarm_threshold_set(
+			PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
+					chip->alarm_low_mv);
+	if (!rc)
+		rc = pm8xxx_batt_alarm_threshold_set(
+			PM8XXX_BATT_ALARM_UPPER_COMPARATOR,
+					chip->alarm_high_mv);
+	if (rc) {
+		pr_err("unable to set batt alarm threshold rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_batt_alarm_hold_time_set(
+				PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
+	if (rc) {
+		pr_err("unable to set batt alarm hold time rc=%d\n", rc);
+		return rc;
+	}
+
+	/* PWM enabled at 2Hz */
+	rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
+	if (rc) {
+		pr_err("unable to set batt alarm pwm rate rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
+	if (rc) {
+		pr_err("unable to register alarm notifier rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
 static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
 {
 	int usb_present;
@@ -2138,6 +2218,61 @@
 	}
 }
 
+static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
+		unsigned long status, void *unused)
+{
+	int rc;
+
+	pr_info("status: %lu\n", status);
+
+	/* Check if called before init */
+
+	switch (status) {
+	case 0:
+		pr_err("spurious interrupt\n");
+		break;
+	/* expected case - trip of low threshold */
+	case 1:
+		if (!the_chip) {
+			pr_err("not initialized\n");
+			return -EINVAL;
+		}
+
+		the_chip->disable_hw_clock_switching = 1;
+
+		rc = pm8xxx_batt_alarm_disable(
+				PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+		if (!rc)
+			rc = pm8xxx_batt_alarm_enable(
+				PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+		if (rc)
+			pr_err("unable to set alarm state rc=%d\n", rc);
+		break;
+	case 2:
+		if (!the_chip) {
+			pr_err("not initialized\n");
+			return -EINVAL;
+		}
+
+		the_chip->disable_hw_clock_switching = 0;
+
+		rc = pm8xxx_batt_alarm_disable(
+				PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+		if (!rc)
+			rc = pm8xxx_batt_alarm_enable(
+				PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+		if (rc)
+			pr_err("unable to set alarm state rc=%d\n", rc);
+
+		pr_err("trip of high threshold\n");
+		break;
+	default:
+		pr_err("error received\n");
+	};
+
+	return 0;
+}
+
 static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
 {
 	u8 temp;
@@ -2308,12 +2443,6 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
-{
-	pr_err("USB OverVoltage\n");
-	return IRQ_HANDLED;
-}
-
 static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
 {
 	struct pm8921_chg_chip *chip = data;
@@ -2358,12 +2487,6 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
-{
-	pr_err("USB UnderVoltage\n");
-	return IRQ_HANDLED;
-}
-
 static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
 {
 	pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
@@ -3050,6 +3173,18 @@
 		return;
 	}
 
+	/* If the disable hw clock switching
+	 * flag was set it can now be unset. Also, re-enable
+	 * the battery alarm to set the flag again when needed
+	 */
+	if (chip->disable_hw_clock_switching) {
+		/* Unset the hw clock switching flag */
+		chip->disable_hw_clock_switching = 0;
+
+		if (pm8921_charger_enable_batt_alarm(chip))
+			pr_err("couldn't set up batt alarm!\n");
+	}
+
 	if (end == CHG_FINISHED) {
 		count++;
 	} else {
@@ -3309,6 +3444,7 @@
 {
 	unsigned long flags;
 	int fsm_state;
+	int is_fast_chg;
 
 	chip->dc_present = !!is_dc_chg_plugged_in(chip);
 	chip->usb_present = !!is_usb_chg_plugged_in(chip);
@@ -3325,8 +3461,6 @@
 	pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
 	pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
 	pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
-	pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
-	pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
 	pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
 	pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
 	pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
@@ -3338,9 +3472,17 @@
 	if (usb_chg_current) {
 		/* reissue a vbus draw call */
 		__pm8921_charger_vbus_draw(usb_chg_current);
-		fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
 	}
 	spin_unlock_irqrestore(&vbus_lock, flags);
+	/*
+	 * The bootloader could have started charging, a fastchg interrupt
+	 * might not happen. Check the real time status and if it is fast
+	 * charging invoke the handler so that the eoc worker could be
+	 * started
+	 */
+	is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
+	if (is_fast_chg)
+		fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
 
 	fsm_state = pm_chg_get_fsm_state(chip);
 	if (is_battery_charging(fsm_state)) {
@@ -3374,13 +3516,10 @@
 struct pm_chg_irq_init_data chg_irq_data[] = {
 	CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 						usbin_valid_irq_handler),
-	CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
 	CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 						batt_inserted_irq_handler),
 	CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 						vbatdet_low_irq_handler),
-	CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-							usbin_uv_irq_handler),
 	CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
 	CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
 	CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
@@ -3961,7 +4100,8 @@
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
 	if (rc)
 		pr_err("Failed to Force Vref therm off rc=%d\n", rc);
-	pm8921_chg_set_hw_clk_switching(chip);
+	if (!(chip->disable_hw_clock_switching))
+		pm8921_chg_set_hw_clk_switching(chip);
 	return 0;
 }
 
@@ -4044,6 +4184,8 @@
 	chip->ttrkl_time = pdata->ttrkl_time;
 	chip->update_time = pdata->update_time;
 	chip->max_voltage_mv = pdata->max_voltage;
+	chip->alarm_low_mv = pdata->alarm_low_mv;
+	chip->alarm_high_mv = pdata->alarm_high_mv;
 	chip->min_voltage_mv = pdata->min_voltage;
 	chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
 	chip->resume_voltage_delta = pdata->resume_voltage_delta;
@@ -4149,8 +4291,6 @@
 
 	enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
-	enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
-	enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
@@ -4166,6 +4306,17 @@
 		}
 	}
 
+	rc = pm8921_charger_configure_batt_alarm(chip);
+	if (rc) {
+		pr_err("Couldn't configure battery alarm! rc=%d\n", rc);
+		goto free_irq;
+	}
+
+	rc = pm8921_charger_enable_batt_alarm(chip);
+	if (rc) {
+		pr_err("Couldn't enable battery alarm! rc=%d\n", rc);
+		goto free_irq;
+	}
 	create_debugfs_entries(chip);
 
 	INIT_WORK(&chip->bms_notify.work, bms_notify);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 45429a1..d099074 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -100,6 +100,7 @@
 	void __iomem		*base;
 	void __iomem		*intr;
 	int			pic_irq;
+	bool			allow_wakeup;
 	spinlock_t		lock;
 	u8			owner;
 	u8			channel;
@@ -638,10 +639,14 @@
 		return -ENODEV;
 	pmic_arb->channel = (u8)prop;
 
-	ret = irq_set_irq_wake(pmic_arb->pic_irq, 1);
-	if (unlikely(ret)) {
-		pr_err("Unable to set wakeup irq, err=%d\n", ret);
-		return -ENODEV;
+	pmic_arb->allow_wakeup = !of_property_read_bool(pdev->dev.of_node,
+					"qcom,not-wakeup");
+	if (pmic_arb->allow_wakeup) {
+		ret = irq_set_irq_wake(pmic_arb->pic_irq, 1);
+		if (unlikely(ret)) {
+			pr_err("Unable to set wakeup irq, err=%d\n", ret);
+			return -ENODEV;
+		}
 	}
 
 	pmic_arb->dev = &pdev->dev;
@@ -685,7 +690,8 @@
 	spmi_del_controller(&pmic_arb->controller);
 err_add_controller:
 	platform_set_drvdata(pdev, NULL);
-	irq_set_irq_wake(pmic_arb->pic_irq, 0);
+	if (pmic_arb->allow_wakeup)
+		irq_set_irq_wake(pmic_arb->pic_irq, 0);
 	return ret;
 }
 
@@ -693,7 +699,8 @@
 {
 	struct spmi_pmic_arb_dev *pmic_arb = platform_get_drvdata(pdev);
 
-	irq_set_irq_wake(pmic_arb->pic_irq, 0);
+	if (pmic_arb->allow_wakeup)
+		irq_set_irq_wake(pmic_arb->pic_irq, 0);
 	platform_set_drvdata(pdev, NULL);
 	spmi_del_controller(&pmic_arb->controller);
 	return 0;
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0c49a89..f60e318 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -907,17 +907,6 @@
 	return 0;
 }
 
-static int tsens_check_version_support(void)
-{
-	int rc = 0;
-
-	if (tmdev->hw_type == MSM_8960)
-		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
-			rc = -ENODEV;
-
-	return rc;
-}
-
 static int tsens_calib_sensors(void)
 {
 	int rc = -ENODEV;
@@ -955,13 +944,6 @@
 	tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
 	tmdev->hw_type = pdata->hw_type;
 
-	rc = tsens_check_version_support();
-	if (rc < 0) {
-		kfree(tmdev);
-		tmdev = NULL;
-		return rc;
-	}
-
 	rc = tsens_calib_sensors();
 	if (rc < 0) {
 		kfree(tmdev);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 7169dc0..77cc1f9 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -10,6 +10,9 @@
  * GNU General Public License for more details.
  *
  */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/thermal.h>
@@ -743,8 +746,7 @@
 					IORESOURCE_MEM, "tsens_physical");
 	if (!tmdev->res_tsens_mem) {
 		pr_err("Could not get tsens physical address resource\n");
-		rc = -EINVAL;
-		goto fail_free_irq;
+		return -EINVAL;
 	}
 
 	tmdev->tsens_len = tmdev->res_tsens_mem->end -
@@ -754,8 +756,7 @@
 				tmdev->tsens_len, tmdev->res_tsens_mem->name);
 	if (!res_mem) {
 		pr_err("Request tsens physical memory region failed\n");
-		rc = -EINVAL;
-		goto fail_free_irq;
+		return -EINVAL;
 	}
 
 	tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
@@ -805,9 +806,6 @@
 	if (tmdev->res_tsens_mem)
 		release_mem_region(tmdev->res_tsens_mem->start,
 					tmdev->tsens_len);
-fail_free_irq:
-	free_irq(tmdev->tsens_irq, tmdev);
-
 	return rc;
 }
 
@@ -827,8 +825,10 @@
 
 	tmdev->pdev = pdev;
 	rc = tsens_calib_sensors();
-	if (rc < 0)
+	if (rc < 0) {
+		pr_err("Calibration failed\n");
 		goto fail;
+	}
 
 	tsens_hw_init();
 
@@ -848,8 +848,7 @@
 	if (tmdev->res_tsens_mem)
 		release_mem_region(tmdev->res_tsens_mem->start,
 			tmdev->tsens_len);
-	free_irq(tmdev->tsens_irq, tmdev);
-	kfree(tmdev);
+	tmdev = NULL;
 
 	return rc;
 }
@@ -930,7 +929,6 @@
 				tmdev->tsens_len);
 	free_irq(tmdev->tsens_irq, tmdev);
 	platform_set_drvdata(pdev, NULL);
-	kfree(tmdev);
 
 	return 0;
 }
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 19e1244..a292416 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1357,6 +1357,9 @@
 {
 	struct usb_device	*udev = to_usb_device(dev);
 
+	if (udev->bus->skip_resume && udev->state == USB_STATE_SUSPENDED)
+		return 0;
+
 	unbind_no_pm_drivers_interfaces(udev);
 
 	/* From now on we are sure all drivers support suspend/resume
@@ -1386,6 +1389,15 @@
 	struct usb_device	*udev = to_usb_device(dev);
 	int			status;
 
+	/*
+	 * Some buses would like to keep their devices in suspend
+	 * state after system resume.  Their resume happen when
+	 * a remote wakeup is detected or interface driver start
+	 * I/O.
+	 */
+	if (udev->bus->skip_resume)
+		return 0;
+
 	/* For all calls, take the device back to full power and
 	 * tell the PM core in case it was autosuspended previously.
 	 * Unbind the interfaces that will need rebinding later,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 0fbe397..817bfbb 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -71,17 +71,19 @@
 #define USB_ETH_RNDIS y
 #include "f_rndis.c"
 #include "rndis.c"
-#include "u_ether.c"
 #include "u_bam_data.c"
 #include "f_mbim.c"
 #include "f_qc_ecm.c"
 #include "f_qc_rndis.c"
+#include "u_ether.c"
 #include "u_qc_ether.c"
 #ifdef CONFIG_TARGET_CORE
 #include "f_tcm.c"
 #endif
+#ifdef CONFIG_SND_PCM
 #include "u_uac1.c"
 #include "f_uac1.c"
+#endif
 
 MODULE_AUTHOR("Mike Lockwood");
 MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -704,6 +706,7 @@
 	.init		= mbim_function_init,
 };
 
+#ifdef CONFIG_SND_PCM
 /* PERIPHERAL AUDIO */
 static int audio_function_bind_config(struct android_usb_function *f,
 					  struct usb_configuration *c)
@@ -715,6 +718,7 @@
 	.name		= "audio",
 	.bind_config	= audio_function_bind_config,
 };
+#endif
 
 
 /* DIAG */
@@ -1520,7 +1524,9 @@
 static struct android_usb_function *supported_functions[] = {
 	&mbim_function,
 	&ecm_qc_function,
+#ifdef CONFIG_SND_PCM
 	&audio_function,
+#endif
 	&rmnet_smd_function,
 	&rmnet_sdio_function,
 	&rmnet_smd_sdio_function,
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b8b7f68..0ace679 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2661,6 +2661,7 @@
 
 	mEp->desc = NULL;
 	mEp->ep.desc = NULL;
+	mEp->ep.maxpacket = USHRT_MAX;
 
 	spin_unlock_irqrestore(mEp->lock, flags);
 	return retval;
@@ -3135,7 +3136,8 @@
 
 			mEp->ep.name      = mEp->name;
 			mEp->ep.ops       = &usb_ep_ops;
-			mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+			mEp->ep.maxpacket =
+				k ? USHRT_MAX : CTRL_PAYLOAD_MAX;
 
 			INIT_LIST_HEAD(&mEp->qh.queue);
 			spin_unlock_irqrestore(udc->lock, flags);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 7fedaf6..1c64955 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -403,6 +403,8 @@
 static void ecm_qc_notify_complete(struct usb_ep *ep, struct usb_request *req)
 {
 	struct f_ecm_qc			*ecm = req->context;
+	struct usb_composite_dev	*cdev = ecm->port.func.config->cdev;
+	struct usb_cdc_notification	*event = req->buf;
 
 	switch (req->status) {
 	case 0:
@@ -584,6 +586,7 @@
 static void ecm_qc_disable(struct usb_function *f)
 {
 	struct f_ecm_qc		*ecm = func_to_ecm_qc(f);
+	struct usb_composite_dev	*cdev = ecm->port.func.config->cdev;
 
 	DBG(cdev, "ecm deactivated\n");
 
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 60b96fe..7a181eb 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -512,8 +512,9 @@
 static void rndis_qc_response_complete(struct usb_ep *ep,
 						struct usb_request *req)
 {
-	struct f_rndis_qc			*rndis = req->context;
+	struct f_rndis_qc		*rndis = req->context;
 	int				status = req->status;
+	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
 
 	/* after TX:
 	 *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index b71f646..5e2c6ed 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -907,13 +907,14 @@
 		 * Register platform driver to be notified in case SMD channels
 		 * later becomes ready to be opened.
 		 */
-		ret = platform_driver_register(&dev->pdrv);
-		if (ret)
-			ERROR(cdev, "Platform driver %s register failed %d\n",
-					dev->pdrv.driver.name, ret);
-		else
-			dev->is_pdrv_used = 1;
-
+		if (!dev->is_pdrv_used) {
+			ret = platform_driver_register(&dev->pdrv);
+			if (ret)
+				ERROR(cdev, "pdrv %s register failed %d\n",
+						dev->pdrv.driver.name, ret);
+			else
+				dev->is_pdrv_used = 1;
+		}
 		return;
 	}
 	wait_event(dev->smd_ctl.wait, test_bit(CH_OPENED,
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 55fd59e..3f4e428 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -294,15 +294,17 @@
 
 static inline enum chg_type usb_get_chg_type(struct usb_info *ui)
 {
-	if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
+	if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
 		return USB_CHG_TYPE__WALLCHARGER;
-	else {
+	} else if (ui->pdata->prop_chg) {
 		if (ui->gadget.speed == USB_SPEED_LOW ||
 			ui->gadget.speed == USB_SPEED_FULL ||
 			ui->gadget.speed == USB_SPEED_HIGH)
 			return USB_CHG_TYPE__SDP;
 		else
 			return USB_CHG_TYPE__INVALID;
+	} else {
+		return USB_CHG_TYPE__SDP;
 	}
 }
 
@@ -332,7 +334,7 @@
 
 	if (temp == USB_CHG_TYPE__WALLCHARGER && !ui->proprietary_chg)
 		return USB_WALLCHARGER_CHG_CURRENT;
-	else
+	else if (ui->pdata->prop_chg)
 		return USB_PROPRIETARY_CHG_CURRENT;
 
 	if (suspended || !configured)
@@ -2049,6 +2051,54 @@
 	.write = debug_reprime_ep,
 };
 
+static ssize_t debug_prop_chg_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char kbuf[2];
+
+	memset(kbuf, 0, sizeof(kbuf));
+
+	if (copy_from_user(kbuf, buf, sizeof(kbuf)))
+		return -EFAULT;
+
+	if (!strncmp(kbuf, "1", 1))
+		ui->pdata->prop_chg = 1;
+	else
+		ui->pdata->prop_chg = 0;
+
+	return count;
+}
+
+static ssize_t debug_prop_chg_read(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct usb_info *ui = file->private_data;
+	char kbuf[2];
+	size_t c = 0;
+
+	memset(kbuf, 0, sizeof(kbuf));
+
+	c = scnprintf(kbuf, sizeof(kbuf), "%d\n", ui->pdata->prop_chg);
+
+	if (copy_to_user(ubuf, kbuf, c))
+		return -EFAULT;
+
+	return simple_read_from_buffer(ubuf, count, ppos, kbuf, c);
+}
+
+static int debug_prop_chg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations debug_prop_chg_ops = {
+	.open = debug_prop_chg_open,
+	.read = debug_prop_chg_read,
+	.write = debug_prop_chg_write,
+};
+
 static void usb_debugfs_init(struct usb_info *ui)
 {
 	struct dentry *dent;
@@ -2063,6 +2113,8 @@
 						&debug_wlocks_ops);
 	debugfs_create_file("prime_fail_countt", 0666, dent, ui,
 						&prime_fail_ops);
+	debugfs_create_file("proprietary_chg", 0666, dent, ui,
+						&debug_prop_chg_ops);
 }
 #else
 static void usb_debugfs_init(struct usb_info *ui) {}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 45dfb87..f092329 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -50,7 +50,7 @@
 
 #define BAM_MUX_RX_Q_SIZE			16
 #define BAM_MUX_TX_Q_SIZE			200
-#define BAM_MUX_RX_REQ_SIZE			(2048 - BAM_MUX_HDR)
+#define BAM_MUX_RX_REQ_SIZE			2048   /* Must be 1KB aligned */
 
 #define DL_INTR_THRESHOLD			20
 
diff --git a/drivers/usb/gadget/u_data_hsuart.c b/drivers/usb/gadget/u_data_hsuart.c
index 74bb93f..4d88ea5 100644
--- a/drivers/usb/gadget/u_data_hsuart.c
+++ b/drivers/usb/gadget/u_data_hsuart.c
@@ -244,9 +244,7 @@
 		pr_debug("%s: port:%p tom:%lu pno:%d\n", __func__,
 				port, port->to_modem, port->port_num);
 
-		spin_unlock_irqrestore(&port->rx_lock, flags);
 		ret = msm_smux_write(port->ch_id, skb, skb->data, skb->len);
-		spin_lock_irqsave(&port->rx_lock, flags);
 		if (ret < 0) {
 			if (ret == -EAGAIN) {
 				/*flow control*/
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index b7f1878..6fe9e58 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -926,6 +926,8 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+
 static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
 {
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1135,6 +1137,13 @@
 	return 0;
 }
 
+#else
+
+#define ehci_hsic_bus_suspend	NULL
+#define ehci_hsic_bus_resume	NULL
+
+#endif	/* CONFIG_PM */
+
 static struct hc_driver msm_hsic_driver = {
 	.description		= hcd_name,
 	.product_desc		= "Qualcomm EHCI Host Controller using HSIC",
@@ -1279,6 +1288,7 @@
 static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
 {
 	struct msm_hsic_hcd *mehci = data;
+	int ret;
 
 	mehci->wakeup_int_cnt++;
 	dbg_log_event(NULL, "Remote Wakeup IRQ", mehci->wakeup_int_cnt);
@@ -1296,8 +1306,17 @@
 	spin_unlock(&mehci->wakeup_lock);
 
 	if (!atomic_read(&mehci->pm_usage_cnt)) {
-		atomic_set(&mehci->pm_usage_cnt, 1);
-		pm_runtime_get(mehci->dev);
+		ret = pm_runtime_get(mehci->dev);
+		/*
+		 * HSIC runtime resume can race with us.
+		 * if we are active (ret == 1) or resuming
+		 * (ret == -EINPROGRESS), decrement the
+		 * PM usage counter before returning.
+		 */
+		if ((ret == 1) || (ret == -EINPROGRESS))
+			pm_runtime_put_noidle(mehci->dev);
+		else
+			atomic_set(&mehci->pm_usage_cnt, 1);
 	}
 
 	return IRQ_HANDLED;
@@ -1522,6 +1541,8 @@
 		return  -ENOMEM;
 	}
 
+	hcd_to_bus(hcd)->skip_resume = true;
+
 	hcd->irq = platform_get_irq(pdev, 0);
 	if (hcd->irq < 0) {
 		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
@@ -1791,6 +1812,15 @@
 	if (device_may_wakeup(dev))
 		disable_irq_wake(hcd->irq);
 
+	/*
+	 * Keep HSIC in Low Power Mode if system is resumed
+	 * by any other wakeup source.  HSIC is resumed later
+	 * when remote wakeup is received or interface driver
+	 * start I/O.
+	 */
+	if (!atomic_read(&mehci->pm_usage_cnt))
+		return 0;
+
 	ret = msm_hsic_resume(mehci);
 	if (ret)
 		return ret;
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 87f43e1c..656e379 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -168,11 +168,10 @@
 		size_t len;
 
 		pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
-		len = min_t(size_t, space, pkt->len);
-		pkt->n_read += len;
+		len = min_t(size_t, space, pkt->len - pkt->n_read);
 		spin_unlock_irqrestore(&ksb->lock, flags);
 
-		ret = copy_to_user(buf + copied, pkt->buf, len);
+		ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
 		if (ret) {
 			pr_err("copy_to_user failed err:%d\n", ret);
 			ksb_free_data_pkt(pkt);
@@ -180,6 +179,7 @@
 			return ret;
 		}
 
+		pkt->n_read += len;
 		space -= len;
 		copied += len;
 
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index f62ae76..ca1b155 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -1229,7 +1229,7 @@
 static irqreturn_t msm_otg_irq(int irq, void *data)
 {
 	struct msm_otg *dev = data;
-	u32 otgsc, sts, pc, sts_mask;
+	u32 otgsc, sts, pc;
 	irqreturn_t ret = IRQ_HANDLED;
 	int work = 0;
 	enum usb_otg_state state;
@@ -1250,12 +1250,16 @@
 	otgsc = readl(USB_OTGSC);
 	sts = readl(USB_USBSTS);
 
-	sts_mask = (otgsc & OTGSC_INTR_MASK) >> 8;
-
-	if (!((otgsc & sts_mask) || (sts & STS_PCI))) {
+	/* At times during USB disconnect, hardware generates 1MSIS interrupt
+	 * during PHY reset, which leads to irq not handled error as IRQ_NONE
+	 * is notified. To workaround this issue, check for all the
+	 * OTG_INTR_STS_MASK bits and if set, clear them and notify IRQ_HANDLED.
+	 */
+	if (!((otgsc & OTGSC_INTR_STS_MASK) || (sts & STS_PCI))) {
 		ret = IRQ_NONE;
 		goto out;
 	}
+	writel_relaxed(otgsc, USB_OTGSC);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	state = dev->phy.state;
@@ -1277,10 +1281,8 @@
 			set_bit(A_BUS_REQ, &dev->inputs);
 			clear_bit(ID, &dev->inputs);
 		}
-		writel(otgsc, USB_OTGSC);
 		work = 1;
 	} else if (otgsc & OTGSC_BSVIS) {
-		writel(otgsc, USB_OTGSC);
 		/* BSV interrupt comes when operating as an A-device
 		 * (VBUS on/off).
 		 * But, handle BSV when charger is removed from ACA in ID_A
@@ -1298,7 +1300,6 @@
 		work = 1;
 	} else if (otgsc & OTGSC_DPIS) {
 		pr_debug("DPIS detected\n");
-		writel(otgsc, USB_OTGSC);
 		set_bit(A_SRP_DET, &dev->inputs);
 		set_bit(A_BUS_REQ, &dev->inputs);
 		work = 1;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 998978c..813fc94 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -52,6 +52,7 @@
 #define DRIVER_NAME	"msm_otg"
 
 #define ID_TIMER_FREQ		(jiffies + msecs_to_jiffies(500))
+#define CHG_RECHECK_DELAY	(jiffies + msecs_to_jiffies(2000))
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
 #define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
 #define USB_PHY_3P3_VOL_MAX	3300000 /* uV */
@@ -76,6 +77,11 @@
 	USB_PHY_REG_LPM_OFF,
 };
 
+static char *override_phy_init;
+module_param(override_phy_init, charp, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(override_phy_init,
+	"Override HSUSB PHY Init Settings");
+
 static DECLARE_COMPLETION(pmic_vbus_init);
 static struct msm_otg *the_msm_otg;
 static bool debug_aca_enabled;
@@ -383,12 +389,26 @@
 static void ulpi_init(struct msm_otg *motg)
 {
 	struct msm_otg_platform_data *pdata = motg->pdata;
-	int *seq = pdata->phy_init_seq;
+	int aseq[10];
+	int *seq = NULL;
+
+	if (override_phy_init) {
+		pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
+				override_phy_init);
+		get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
+		seq = &aseq[1];
+	} else {
+		seq = pdata->phy_init_seq;
+	}
 
 	if (!seq)
 		return;
 
 	while (seq[0] >= 0) {
+		if (override_phy_init)
+			pr_debug("ulpi: write 0x%02x to 0x%02x\n",
+					seq[0], seq[1]);
+
 		dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
 				seq[0], seq[1]);
 		ulpi_write(&motg->phy, seq[0], seq[1]);
@@ -1629,6 +1649,26 @@
 	return ret;
 }
 
+static void msm_otg_chg_check_timer_func(unsigned long data)
+{
+	struct msm_otg *motg = (struct msm_otg *) data;
+	struct usb_otg *otg = motg->phy.otg;
+
+	if (atomic_read(&motg->in_lpm) ||
+		!test_bit(B_SESS_VLD, &motg->inputs) ||
+		otg->phy->state != OTG_STATE_B_PERIPHERAL ||
+		otg->gadget->speed != USB_SPEED_UNKNOWN) {
+		dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
+		return;
+	}
+
+	if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
+		dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
+		set_bit(B_FALSE_SDP, &motg->inputs);
+		queue_work(system_nrt_wq, &motg->sm_work);
+	}
+}
+
 static bool msm_chg_aca_detect(struct msm_otg *motg)
 {
 	struct usb_phy *phy = &motg->phy;
@@ -2347,6 +2387,8 @@
 					msm_otg_start_peripheral(otg, 1);
 					otg->phy->state =
 						OTG_STATE_B_PERIPHERAL;
+					mod_timer(&motg->chg_check_timer,
+							CHG_RECHECK_DELAY);
 					break;
 				default:
 					break;
@@ -2367,6 +2409,8 @@
 			break;
 		} else {
 			pr_debug("chg_work cancel");
+			del_timer_sync(&motg->chg_check_timer);
+			clear_bit(B_FALSE_SDP, &motg->inputs);
 			cancel_delayed_work_sync(&motg->chg_work);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
 			motg->chg_type = USB_INVALID_CHARGER;
@@ -2404,7 +2448,15 @@
 		}
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		if (!test_bit(ID, &motg->inputs) ||
+		if (test_bit(B_SESS_VLD, &motg->inputs) &&
+				test_bit(B_FALSE_SDP, &motg->inputs)) {
+			pr_debug("B_FALSE_SDP\n");
+			msm_otg_start_peripheral(otg, 0);
+			motg->chg_type = USB_DCP_CHARGER;
+			clear_bit(B_FALSE_SDP, &motg->inputs);
+			otg->phy->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else if (!test_bit(ID, &motg->inputs) ||
 				test_bit(ID_A, &motg->inputs) ||
 				test_bit(ID_B, &motg->inputs) ||
 				!test_bit(B_SESS_VLD, &motg->inputs)) {
@@ -3709,6 +3761,8 @@
 	INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
 	setup_timer(&motg->id_timer, msm_otg_id_timer_func,
 				(unsigned long) motg);
+	setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
+				(unsigned long) motg);
 	ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
 					"msm_otg", motg);
 	if (ret) {
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 54d7090..ed4c25d 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -820,14 +820,6 @@
 	---help---
 	  Support for DVI mode for MSM HDMI 1080p Panel
 
-config FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	depends on FB_MSM_HDMI_MSM_PANEL
-	bool "Use HDCP mode"
-	default y
-	---help---
-	  Support for HDCP mode for MSM HDMI 1080p Panel
-	  Choose to enable HDCP
-
 config FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 	depends on FB_MSM_HDMI_MSM_PANEL
 	bool "Enable CEC"
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 902e92c..deef4ab 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -60,18 +60,16 @@
 struct workqueue_struct *hdmi_work_queue;
 struct hdmi_msm_state_type *hdmi_msm_state;
 
+/* Enable HDCP by default */
+static bool hdcp_feature_on = true;
+
 DEFINE_MUTEX(hdmi_msm_state_mutex);
 EXPORT_SYMBOL(hdmi_msm_state_mutex);
 static DEFINE_MUTEX(hdcp_auth_state_mutex);
 
 static void hdmi_msm_dump_regs(const char *prefix);
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 static void hdmi_msm_hdcp_enable(void);
-#else
-static inline void hdmi_msm_hdcp_enable(void) {}
-#endif
-
 static void hdmi_msm_turn_on(void);
 static int hdmi_msm_audio_off(void);
 static int hdmi_msm_read_edid(void);
@@ -675,7 +673,6 @@
 	case 0x00D8: return "ACR_48_1";
 	case 0x00E4: return "AUDIO_INFO0";
 	case 0x00E8: return "AUDIO_INFO1";
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	case 0x0110: return "HDCP_CTRL";
 	case 0x0114: return "HDCP_DEBUG_CTRL";
 	case 0x0118: return "HDCP_INT_CTRL";
@@ -690,7 +687,6 @@
 	case 0x014C: return "HDCP_RCVPORT_DATA5";
 	case 0x0150: return "HDCP_RCVPORT_DATA6";
 	case 0x0168: return "HDCP_RCVPORT_DATA12";
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 	case 0x01D0: return "AUDIO_CFG";
 	case 0x0208: return "USEC_REFTIMER";
 	case 0x020C: return "DDC_CTRL";
@@ -705,14 +701,10 @@
 	case 0x0250: return "HPD_INT_STATUS";
 	case 0x0254: return "HPD_INT_CTRL";
 	case 0x0258: return "HPD_CTRL";
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	case 0x025C: return "HDCP_ENTROPY_CTRL1";
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 	case 0x027C: return "DDC_REF";
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	case 0x0284: return "HDCP_SW_UPPER_AKSV";
 	case 0x0288: return "HDCP_SW_LOWER_AKSV";
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 	case 0x02B4: return "ACTIVE_H";
 	case 0x02B8: return "ACTIVE_V";
 	case 0x02BC: return "ACTIVE_V_F2";
@@ -781,7 +773,7 @@
 
 		DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
 		kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE);
-		if (!external_common_state->present_hdcp) {
+		if (!hdmi_msm_state->hdcp_enable) {
 			/* Send Audio for HDMI Compliance Cases*/
 			envp[0] = "HDCP_STATE=PASS";
 			envp[1] = NULL;
@@ -870,10 +862,13 @@
 }
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 static void hdcp_deauthenticate(void);
 static void hdmi_msm_hdcp_reauth_work(struct work_struct *work)
 {
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
 
 	/* Don't process recursive actions */
 	mutex_lock(&hdmi_msm_state_mutex);
@@ -891,17 +886,20 @@
 	 * Therefore, as surprising as it may sound do reauth
 	 * only if the device is HDCP-capable
 	 */
-	if (external_common_state->present_hdcp) {
-		hdcp_deauthenticate();
-		mutex_lock(&hdcp_auth_state_mutex);
-		hdmi_msm_state->reauth = TRUE;
-		mutex_unlock(&hdcp_auth_state_mutex);
-		mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
-	}
+	hdcp_deauthenticate();
+	mutex_lock(&hdcp_auth_state_mutex);
+	hdmi_msm_state->reauth = TRUE;
+	mutex_unlock(&hdcp_auth_state_mutex);
+	mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
 }
 
 static void hdmi_msm_hdcp_work(struct work_struct *work)
 {
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
+
 	/* Only re-enable if cable still connected */
 	mutex_lock(&external_common_state_hpd_mutex);
 	if (external_common_state->hpd_state &&
@@ -922,7 +920,111 @@
 		hdmi_msm_state->reauth = FALSE;
 	}
 }
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
+
+int hdmi_msm_process_hdcp_interrupts(void)
+{
+	int rc = -1;
+	uint32 hdcp_int_val;
+	char *envp[2];
+
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return -EINVAL;
+	}
+
+	/* HDCP_INT_CTRL[0x0118]
+	 *    [0] AUTH_SUCCESS_INT	[R]	HDCP Authentication Success
+	 *		interrupt status
+	 *    [1] AUTH_SUCCESS_ACK	[W]	Acknowledge bit for HDCP
+	 *		Authentication Success bit - write 1 to clear
+	 *    [2] AUTH_SUCCESS_MASK	[R/W]	Mask bit for HDCP Authentication
+	 *		Success interrupt - set to 1 to enable interrupt */
+	hdcp_int_val = HDMI_INP_ND(0x0118);
+	if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) {
+		/* AUTH_SUCCESS_INT */
+		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0));
+		DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n");
+		complete_all(&hdmi_msm_state->hdcp_success_done);
+		return 0;
+	}
+
+	/*    [4] AUTH_FAIL_INT		[R]	HDCP Authentication Lost
+	 *		interrupt Status
+	 *    [5] AUTH_FAIL_ACK		[W]	Acknowledge bit for HDCP
+	 *		Authentication Lost bit - write 1 to clear
+	 *    [6] AUTH_FAIL_MASK	[R/W]	Mask bit fo HDCP Authentication
+	 *		Lost interrupt set to 1 to enable interrupt
+	 *    [7] AUTH_FAIL_INFO_ACK	[W]	Acknowledge bit for HDCP
+	 *		Authentication Failure Info field - write 1 to clear */
+	if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) {
+		/* AUTH_FAIL_INT */
+		/* Clear and Disable */
+		uint32 link_status = HDMI_INP_ND(0x011C);
+		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5))
+			& ~((1 << 6) | (1 << 4)));
+		DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
+			link_status);
+		if (hdmi_msm_state->full_auth_done) {
+			switch_set_state(&external_common_state->sdev, 0);
+			DEV_INFO("Hdmi state switched to %d: %s\n",
+				external_common_state->sdev.state,  __func__);
+
+			envp[0] = "HDCP_STATE=FAIL";
+			envp[1] = NULL;
+			DEV_INFO("HDMI HPD:QDSP OFF\n");
+			kobject_uevent_env(external_common_state->uevent_kobj,
+			KOBJ_CHANGE, envp);
+
+			mutex_lock(&hdcp_auth_state_mutex);
+			hdmi_msm_state->full_auth_done = FALSE;
+			mutex_unlock(&hdcp_auth_state_mutex);
+			/* Calling reauth only when authentication
+			 * is sucessful or else we always go into
+			 * the reauth loop. Also, No need to reauthenticate
+			 * if authentication failed because of cable disconnect
+			 */
+			if (((link_status & 0xF0) >> 4) != 0x7) {
+				DEV_DBG("Reauthenticate From %s HDCP FAIL INT ",
+					__func__);
+				queue_work(hdmi_work_queue,
+				    &hdmi_msm_state->hdcp_reauth_work);
+			} else {
+				DEV_INFO("HDCP: HDMI cable disconnected\n");
+			}
+		}
+
+		/* Clear AUTH_FAIL_INFO as well */
+		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
+		return 0;
+	}
+
+	/*    [8] DDC_XFER_REQ_INT	[R]	HDCP DDC Transfer Request
+	 *		interrupt status
+	 *    [9] DDC_XFER_REQ_ACK	[W]	Acknowledge bit for HDCP DDC
+	 *		Transfer Request bit - write 1 to clear
+	 *   [10] DDC_XFER_REQ_MASK	[R/W]	Mask bit for HDCP DDC Transfer
+	 *		Request interrupt - set to 1 to enable interrupt */
+	if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) {
+		/* DDC_XFER_REQ_INT */
+		HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8));
+		if (!(hdcp_int_val & (1 << 12)))
+			return 0;
+	}
+	/*   [12] DDC_XFER_DONE_INT	[R]	HDCP DDC Transfer done interrupt
+	 *		status
+	 *   [13] DDC_XFER_DONE_ACK	[W]	Acknowledge bit for HDCP DDC
+	 *		Transfer done bit - write 1 to clear
+	 *   [14] DDC_XFER_DONE_MASK	[R/W]	Mask bit for HDCP DDC Transfer
+	 *		done interrupt - set to 1 to enable interrupt */
+	if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) {
+		/* DDC_XFER_DONE_INT */
+		HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12));
+		DEV_INFO("HDCP: DDC_XFER_DONE received\n");
+		return 0;
+	}
+
+	return rc;
+}
 
 static irqreturn_t hdmi_msm_isr(int irq, void *dev_id)
 {
@@ -933,10 +1035,6 @@
 #endif
 	uint32 ddc_int_ctrl;
 	uint32 audio_int_val;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	uint32 hdcp_int_val;
-	char *envp[2];
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 	static uint32 fifo_urun_int_occurred;
 	static uint32 sample_drop_int_occurred;
 	const uint32 occurrence_limit = 5;
@@ -1054,96 +1152,8 @@
 		return IRQ_HANDLED;
 	}
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	/* HDCP_INT_CTRL[0x0118]
-	 *    [0] AUTH_SUCCESS_INT	[R]	HDCP Authentication Success
-	 *		interrupt status
-	 *    [1] AUTH_SUCCESS_ACK	[W]	Acknowledge bit for HDCP
-	 *		Authentication Success bit - write 1 to clear
-	 *    [2] AUTH_SUCCESS_MASK	[R/W]	Mask bit for HDCP Authentication
-	 *		Success interrupt - set to 1 to enable interrupt */
-	hdcp_int_val = HDMI_INP_ND(0x0118);
-	if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) {
-		/* AUTH_SUCCESS_INT */
-		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0));
-		DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n");
-		complete_all(&hdmi_msm_state->hdcp_success_done);
+	if (!hdmi_msm_process_hdcp_interrupts())
 		return IRQ_HANDLED;
-	}
-	/*    [4] AUTH_FAIL_INT		[R]	HDCP Authentication Lost
-	 *		interrupt Status
-	 *    [5] AUTH_FAIL_ACK		[W]	Acknowledge bit for HDCP
-	 *		Authentication Lost bit - write 1 to clear
-	 *    [6] AUTH_FAIL_MASK	[R/W]	Mask bit fo HDCP Authentication
-	 *		Lost interrupt set to 1 to enable interrupt
-	 *    [7] AUTH_FAIL_INFO_ACK	[W]	Acknowledge bit for HDCP
-	 *		Authentication Failure Info field - write 1 to clear */
-	if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) {
-		/* AUTH_FAIL_INT */
-		/* Clear and Disable */
-		uint32 link_status = HDMI_INP_ND(0x011C);
-		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5))
-			& ~((1 << 6) | (1 << 4)));
-		DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
-			link_status);
-		if (hdmi_msm_state->full_auth_done) {
-			switch_set_state(&external_common_state->sdev, 0);
-			DEV_INFO("Hdmi state switched to %d: %s\n",
-				external_common_state->sdev.state,  __func__);
-
-			envp[0] = "HDCP_STATE=FAIL";
-			envp[1] = NULL;
-			DEV_INFO("HDMI HPD:QDSP OFF\n");
-			kobject_uevent_env(external_common_state->uevent_kobj,
-			KOBJ_CHANGE, envp);
-
-			mutex_lock(&hdcp_auth_state_mutex);
-			hdmi_msm_state->full_auth_done = FALSE;
-			mutex_unlock(&hdcp_auth_state_mutex);
-			/* Calling reauth only when authentication
-			 * is sucessful or else we always go into
-			 * the reauth loop. Also, No need to reauthenticate
-			 * if authentication failed because of cable disconnect
-			 */
-			if (((link_status & 0xF0) >> 4) != 0x7) {
-				DEV_DBG("Reauthenticate From %s HDCP FAIL INT ",
-					__func__);
-				queue_work(hdmi_work_queue,
-				    &hdmi_msm_state->hdcp_reauth_work);
-			} else {
-				DEV_INFO("HDCP: HDMI cable disconnected\n");
-			}
-		}
-
-		/* Clear AUTH_FAIL_INFO as well */
-		HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
-		return IRQ_HANDLED;
-	}
-	/*    [8] DDC_XFER_REQ_INT	[R]	HDCP DDC Transfer Request
-	 *		interrupt status
-	 *    [9] DDC_XFER_REQ_ACK	[W]	Acknowledge bit for HDCP DDC
-	 *		Transfer Request bit - write 1 to clear
-	 *   [10] DDC_XFER_REQ_MASK	[R/W]	Mask bit for HDCP DDC Transfer
-	 *		Request interrupt - set to 1 to enable interrupt */
-	if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) {
-		/* DDC_XFER_REQ_INT */
-		HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8));
-		if (!(hdcp_int_val & (1 << 12)))
-			return IRQ_HANDLED;
-	}
-	/*   [12] DDC_XFER_DONE_INT	[R]	HDCP DDC Transfer done interrupt
-	 *		status
-	 *   [13] DDC_XFER_DONE_ACK	[W]	Acknowledge bit for HDCP DDC
-	 *		Transfer done bit - write 1 to clear
-	 *   [14] DDC_XFER_DONE_MASK	[R/W]	Mask bit for HDCP DDC Transfer
-	 *		done interrupt - set to 1 to enable interrupt */
-	if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) {
-		/* DDC_XFER_DONE_INT */
-		HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12));
-		DEV_INFO("HDCP: DDC_XFER_DONE received\n");
-		return IRQ_HANDLED;
-	}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 	/* Process CEC Interrupt */
@@ -1302,7 +1312,7 @@
 		if (external_common_state->hdmi_sink == 0) {
 			/* HDMI_DVI_SEL */
 			reg_val |= 0x00000002;
-			if (external_common_state->present_hdcp)
+			if (hdmi_msm_state->hdcp_enable)
 				/* HDMI Encryption */
 				reg_val |= 0x00000004;
 			/* HDMI_CTRL */
@@ -1310,7 +1320,7 @@
 			/* HDMI_DVI_SEL */
 			reg_val &= ~0x00000002;
 		} else {
-			if (external_common_state->present_hdcp)
+			if (hdmi_msm_state->hdcp_enable)
 				/* HDMI_Encryption_ON */
 				reg_val |= 0x00000006;
 			else
@@ -1390,7 +1400,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 static int hdmi_msm_ddc_write(uint32 dev_addr, uint32 offset,
 	const uint8 *data_buf, uint32 data_len, const char *what)
 {
@@ -1586,7 +1595,6 @@
 error:
 	return status;
 }
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 static int hdmi_msm_ddc_read_retry(uint32 dev_addr, uint32 offset,
 	uint8 *data_buf, uint32 data_len, uint32 request_len, int retry,
@@ -2147,9 +2155,13 @@
 	return status;
 }
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 static void hdcp_auth_info(uint32 auth_info)
 {
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
+
 	switch (auth_info) {
 	case 0:
 		DEV_INFO("%s: None", __func__);
@@ -2184,6 +2196,11 @@
 
 static void hdcp_key_state(uint32 key_state)
 {
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
+
 	switch (key_state) {
 	case 0:
 		DEV_WARN("%s: No HDCP Keys", __func__);
@@ -2227,6 +2244,11 @@
 {
 	int hdcp_link_status = HDMI_INP(0x011C);
 
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
+
 	/* Disable HDCP interrupts */
 	HDMI_OUTP(0x0118, 0x0);
 
@@ -2254,6 +2276,11 @@
 	int failure;
 	int nack0;
 
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
+
 	/*
 	 * Check for any DDC transfer failures
 	 * 0x0128 HDCP_DDC_STATUS
@@ -2364,6 +2391,11 @@
 	static uint8 buf[0xFF];
 	memset(buf, 0, sizeof(buf));
 
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return 0;
+	}
+
 	if (!is_part1_done) {
 		is_part1_done = TRUE;
 
@@ -2651,6 +2683,11 @@
 	int ret;
 	uint8 buf[4];
 
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return 0;
+	}
+
 	snprintf(what, sizeof(what), "V' H0");
 	ret = hdmi_msm_ddc_read(0x74, 0x20, buf, 4, 5, what, TRUE);
 	if (ret) {
@@ -2743,6 +2780,11 @@
 
 	boolean ksv_done = FALSE;
 
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return 0;
+	}
+
 	memset(buf, 0, sizeof(buf));
 	memset(kvs_fifo, 0, sizeof(kvs_fifo));
 
@@ -2935,6 +2977,12 @@
 {
 	int ret = 0;
 	int poll = 3000;
+
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return 0;
+	}
+
 	while (poll) {
 		/* 0x011C HDCP_LINK0_STATUS
 		    [30:28]  KEYS_STATE = 3 = "Valid"
@@ -2965,7 +3013,7 @@
 	uint32 found_repeater = 0x0;
 	char *envp[2];
 
-	if (!hdmi_msm_has_hdcp()) {
+	if (!hdmi_msm_state->hdcp_enable) {
 		DEV_INFO("%s: HDCP NOT ENABLED\n", __func__);
 		return;
 	}
@@ -3066,7 +3114,6 @@
 	DEV_INFO("Hdmi state switched to %d: %s\n",
 		external_common_state->sdev.state, __func__);
 }
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 static void hdmi_msm_video_setup(int video_format)
 {
@@ -3584,11 +3631,9 @@
 {
 	msm_hdmi_sample_rate = rate;
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	if (hdmi_msm_has_hdcp())
+	if (hdmi_msm_state->hdcp_enable)
 		hdcp_deauthenticate();
 	else
-#endif
 		hdmi_msm_turn_on();
 }
 EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset);
@@ -4158,12 +4203,10 @@
 #endif
 	hdmi_msm_spd_infoframe_packetsetup();
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	if (hdmi_msm_state->reauth) {
+	if (hdmi_msm_state->hdcp_enable && hdmi_msm_state->reauth) {
 		hdmi_msm_hdcp_enable();
 		hdmi_msm_state->reauth = FALSE ;
 	}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 	/* re-initialize CEC if enabled */
@@ -4208,12 +4251,15 @@
 	}
 }
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 static void hdmi_msm_hdcp_timer(unsigned long data)
 {
+	if (!hdmi_msm_state->hdcp_enable) {
+		DEV_DBG("%s: HDCP not enabled\n", __func__);
+		return;
+	}
+
 	queue_work(hdmi_work_queue, &hdmi_msm_state->hdcp_work);
 }
-#endif
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 static void hdmi_msm_cec_read_timer_func(unsigned long data)
@@ -4378,12 +4424,14 @@
 		mutex_unlock(&external_common_state_hpd_mutex);
 		hdmi_msm_turn_on();
 
-		/* Kick off HDCP Authentication */
-		mutex_lock(&hdcp_auth_state_mutex);
-		hdmi_msm_state->reauth = FALSE;
-		hdmi_msm_state->full_auth_done = FALSE;
-		mutex_unlock(&hdcp_auth_state_mutex);
-		mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
+		if (hdmi_msm_state->hdcp_enable) {
+			/* Kick off HDCP Authentication */
+			mutex_lock(&hdcp_auth_state_mutex);
+			hdmi_msm_state->reauth = FALSE;
+			hdmi_msm_state->full_auth_done = FALSE;
+			mutex_unlock(&hdcp_auth_state_mutex);
+			mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
+		}
 	} else
 		mutex_unlock(&external_common_state_hpd_mutex);
 
@@ -4407,16 +4455,14 @@
 		 external_common_state->sdev.state,  __func__);
 	if (on) {
 		hdmi_msm_read_edid();
-		if (hdmi_msm_has_hdcp())
-			hdmi_msm_state->reauth = FALSE ;
+		hdmi_msm_state->reauth = FALSE ;
 		/* Build EDID table */
 		hdmi_msm_turn_on();
 		DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
 		kobject_uevent(external_common_state->uevent_kobj,
 			       KOBJ_ONLINE);
-		hdmi_msm_hdcp_enable();
 		envp[0] = 0;
-		if (!hdmi_msm_has_hdcp()) {
+		if (!hdmi_msm_state->hdcp_enable) {
 			/* Send Audio for HDMI Compliance Cases*/
 			envp[0] = "HDCP_STATE=PASS";
 			envp[1] = NULL;
@@ -4426,6 +4472,8 @@
 			switch_set_state(&external_common_state->sdev, 1);
 			DEV_INFO("Hdmi state switched to %d: %s\n",
 				 external_common_state->sdev.state, __func__);
+		} else {
+			hdmi_msm_hdcp_enable();
 		}
 	} else {
 		DEV_INFO("HDMI HPD: DISCONNECTED: send OFFLINE\n");
@@ -4449,7 +4497,6 @@
 	if (!hdmi_msm_state->hdmi_app_clk)
 		return -ENODEV;
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	mutex_lock(&hdmi_msm_state_mutex);
 	if (hdmi_msm_state->hdcp_activating) {
 		hdmi_msm_state->panel_power_on = FALSE;
@@ -4458,13 +4505,10 @@
 		return 0;
 	}
 	mutex_unlock(&hdmi_msm_state_mutex);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 	DEV_INFO("power: OFF (audio off, Reset Core)\n");
 	hdmi_msm_audio_off();
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	hdcp_deauthenticate();
-#endif
 	hdmi_msm_powerdown_phy();
 
 	hdmi_msm_state->panel_power_on = FALSE;
@@ -4476,6 +4520,28 @@
 	return hdmi_msm_state->is_mhl_enabled;
 }
 
+void hdmi_msm_config_hdcp_feature(void)
+{
+	if (hdcp_feature_on && hdmi_msm_has_hdcp()) {
+		init_timer(&hdmi_msm_state->hdcp_timer);
+		hdmi_msm_state->hdcp_timer.function = hdmi_msm_hdcp_timer;
+		hdmi_msm_state->hdcp_timer.data = (uint32)NULL;
+		hdmi_msm_state->hdcp_timer.expires = 0xffffffffL;
+
+		init_completion(&hdmi_msm_state->hdcp_success_done);
+		INIT_WORK(&hdmi_msm_state->hdcp_reauth_work,
+				hdmi_msm_hdcp_reauth_work);
+		INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work);
+		hdmi_msm_state->hdcp_enable = TRUE;
+	} else {
+		del_timer(&hdmi_msm_state->hdcp_timer);
+		hdmi_msm_state->hdcp_enable = FALSE;
+	}
+	external_common_state->present_hdcp = hdmi_msm_state->hdcp_enable;
+	DEV_INFO("%s: HDCP Feature: %s\n", __func__,
+			hdmi_msm_state->hdcp_enable ? "Enabled" : "Disabled");
+}
+
 static int __devinit hdmi_msm_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -4588,15 +4654,6 @@
 
 	hdmi_msm_state->hpd_state_timer.expires = 0xffffffffL;
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	init_timer(&hdmi_msm_state->hdcp_timer);
-	hdmi_msm_state->hdcp_timer.function =
-		hdmi_msm_hdcp_timer;
-	hdmi_msm_state->hdcp_timer.data = (uint32)NULL;
-
-	hdmi_msm_state->hdcp_timer.expires = 0xffffffffL;
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
-
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 	init_timer(&hdmi_msm_state->cec_read_timer);
 	hdmi_msm_state->cec_read_timer.function =
@@ -4623,22 +4680,7 @@
 			goto error;
 	}
 
-	if (hdmi_msm_has_hdcp()) {
-		/* Don't Set Encryption in case of non HDCP builds */
-		external_common_state->present_hdcp = FALSE;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-		external_common_state->present_hdcp = TRUE;
-#endif
-	} else {
-		external_common_state->present_hdcp = FALSE;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-		/*
-		 * If the device is not hdcp capable do
-		 * not start hdcp timer.
-		 */
-		del_timer(&hdmi_msm_state->hdcp_timer);
-#endif
-	}
+	hdmi_msm_config_hdcp_feature();
 
 	/* Initialize hdmi node and register with switch driver */
 	if (hdmi_prim_display)
@@ -4822,11 +4864,6 @@
 	hdmi_common_init_panel_info(&hdmi_msm_panel_data.panel_info);
 	init_completion(&hdmi_msm_state->ddc_sw_done);
 	INIT_WORK(&hdmi_msm_state->hpd_state_work, hdmi_msm_hpd_state_work);
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	init_completion(&hdmi_msm_state->hdcp_success_done);
-	INIT_WORK(&hdmi_msm_state->hdcp_reauth_work, hdmi_msm_hdcp_reauth_work);
-	INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 	INIT_WORK(&hdmi_msm_state->cec_latch_detect_work,
@@ -4850,9 +4887,6 @@
 		" RELEASE"
 #endif
 		" AUDIO EDID HPD HDCP"
-#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-		":0"
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 		" DVI"
 #ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT
 		":0"
@@ -4874,6 +4908,36 @@
 	platform_driver_unregister(&this_driver);
 }
 
+static int set_hdcp_feature_on(const char *val, const struct kernel_param *kp)
+{
+	int rv = param_set_bool(val, kp);
+
+	if (rv)
+		return rv;
+
+	pr_debug("%s: HDCP feature = %d\n", __func__, hdcp_feature_on);
+	if (hdmi_msm_state) {
+		if ((HDMI_INP(0x0250) & 0x2)) {
+			pr_err("%s: Unable to set HDCP feature", __func__);
+			pr_err("%s: HDMI panel is currently turned on",
+					__func__);
+		} else if (hdcp_feature_on != hdmi_msm_state->hdcp_enable) {
+			hdmi_msm_config_hdcp_feature();
+		}
+	}
+
+	return 0;
+}
+
+static struct kernel_param_ops hdcp_feature_on_param_ops = {
+	.set = set_hdcp_feature_on,
+	.get = param_get_bool,
+};
+
+module_param_cb(hdcp, &hdcp_feature_on_param_ops, &hdcp_feature_on,
+			S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(hdcp, "Enable or Disable HDCP");
+
 module_init(hdmi_msm_init);
 module_exit(hdmi_msm_exit);
 
diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 5d27412..20bd492 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -64,13 +64,12 @@
 	struct timer_list hpd_state_timer;
 	struct completion ddc_sw_done;
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
+	bool hdcp_enable;
 	boolean hdcp_activating;
 	boolean reauth ;
 	struct work_struct hdcp_reauth_work, hdcp_work;
 	struct completion hdcp_success_done;
 	struct timer_list hdcp_timer;
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
 	boolean cec_enabled;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index f6d9eb7..6c0d08d 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -35,6 +35,7 @@
 #include <asm/mach-types.h>
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
+#include <mach/event_timer.h>
 #include <mach/clk.h>
 #include "mdp.h"
 #include "msm_fb.h"
@@ -183,7 +184,7 @@
 		base = 0x18000;
 		break;
 	case MDP_BLOCK_OVERLAY_2:
-		base = (mdp_rev >= MDP_REV_44) ? 0x88000 : 0;
+		base = (mdp_rev >= MDP_REV_43) ? 0x88000 : 0;
 		break;
 	default:
 		break;
@@ -518,7 +519,9 @@
 	int ret;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	ret = mdp_lut_hw_update(cmap);
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (ret)
@@ -540,9 +543,11 @@
 	uint32_t out;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	ret = mdp_lut_hw_update(cmap);
 
 	if (ret) {
+		mdp_clk_ctrl(0);
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 		return ret;
 	}
@@ -550,6 +555,7 @@
 	/*mask off non LUT select bits*/
 	out = inpdw(MDP_BASE + 0x90070);
 	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
 
@@ -1066,6 +1072,7 @@
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	for (i = 0; i < mgmt->num_bins; i++) {
 		mgmt->c0[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
 		mgmt->c1[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
@@ -1081,6 +1088,7 @@
 		} else
 			ret = -ENOMEM;
 	}
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (!ret)
@@ -1116,6 +1124,7 @@
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	for (i = 0; i < mgmt->num_bins; i++)
 		mgmt->c0[i] = inpdw(mdp_hist_base + MDP_HIST_DATA_LUMA_OFF +
 									(4*i));
@@ -1127,6 +1136,7 @@
 		} else
 			ret = -ENOMEM;
 	}
+	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (!ret)
@@ -1315,27 +1325,32 @@
 }
 #endif
 
-static void send_vsync_work(struct work_struct *work)
-{
-	char buf[64];
-	char *envp[2];
-
-	snprintf(buf, sizeof(buf), "VSYNC=%llu",
-			ktime_to_ns(vsync_cntrl.vsync_time));
-	envp[0] = buf;
-	envp[1] = NULL;
-	kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp);
-}
-
 #ifdef CONFIG_FB_MSM_MDP303
 /* vsync_isr_handler: Called from isr context*/
 static void vsync_isr_handler(void)
 {
 	vsync_cntrl.vsync_time = ktime_get();
-	schedule_work(&(vsync_cntrl.vsync_work));
 }
 #endif
 
+static ssize_t vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	if (atomic_read(&vsync_cntrl.suspend) > 0 ||
+		atomic_read(&vsync_cntrl.vsync_resume) == 0)
+		return 0;
+
+	INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
+	wait_for_completion(&vsync_cntrl.vsync_wait);
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+			ktime_to_ns(vsync_cntrl.vsync_time));
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
+}
+
 /* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
 int mdp_ppp_pipe_wait(void)
 {
@@ -1352,15 +1367,95 @@
 	if (wait == TRUE) {
 		ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp,
 								5 * HZ);
-
 		if (!ret)
 			printk(KERN_ERR "%s: Timed out waiting for the MDP.\n",
-					__func__);
+				__func__);
 	}
 
 	return ret;
 }
 
+#define MAX_VSYNC_GAP		4
+#define DEFAULT_FRAME_RATE	60
+
+static u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
+{
+	u32 frame_rate = 0, total_pixel;
+	struct msm_panel_info *panel_info = &mfd->panel_info;
+	if (mfd->dest == DISPLAY_LCD) {
+		if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
+			frame_rate = panel_info->lcd.refx100 / (100 * 2);
+		else
+			frame_rate = panel_info->lcd.refx100 / 100;
+	} else {
+		if (panel_info->type == MIPI_VIDEO_PANEL) {
+			frame_rate = panel_info->mipi.frame_rate;
+		} else {
+			total_pixel = (panel_info->lcdc.h_back_porch +
+				  panel_info->lcdc.h_front_porch +
+				  panel_info->lcdc.h_pulse_width +
+				  panel_info->xres) *
+				 (panel_info->lcdc.v_back_porch +
+				  panel_info->lcdc.v_front_porch +
+				  panel_info->lcdc.v_pulse_width +
+				  panel_info->yres);
+			if (total_pixel)
+				frame_rate = panel_info->clk_rate /
+					total_pixel;
+		}
+	}
+	if (frame_rate == 0)
+		frame_rate = DEFAULT_FRAME_RATE;
+	return frame_rate;
+}
+
+static int mdp_diff_to_next_vsync(ktime_t cur_time,
+			ktime_t last_vsync, u32 vsync_period)
+{
+	int diff_from_last, diff_to_next;
+	/*
+	 * Get interval beween last vsync and current time
+	 * Current time = CPU programming MDP for next Vsync
+	 */
+	diff_from_last =
+		(ktime_to_us(ktime_sub(cur_time, last_vsync)));
+	diff_from_last /= USEC_PER_MSEC;
+	/*
+	 * If the last Vsync occurred too long ago, skip programming
+	 * the timer
+	 */
+	if (diff_from_last < (vsync_period * MAX_VSYNC_GAP)) {
+		if (diff_from_last > vsync_period)
+			diff_to_next =
+				(diff_from_last - vsync_period) % vsync_period;
+		else
+			diff_to_next = vsync_period - diff_from_last;
+	} else {
+		/* mark it out of range */
+		diff_to_next = vsync_period + 1;
+	}
+	return diff_to_next;
+}
+
+void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync)
+{
+	u32 vsync_period;
+	int diff_to_next;
+	ktime_t cur_time, wakeup_time;
+
+	if (!mfd->cpu_pm_hdl)
+		return;
+	vsync_period = mfd->panel_info.frame_interval;
+	cur_time = ktime_get();
+	diff_to_next = mdp_diff_to_next_vsync(cur_time,
+					      pre_vsync,
+					      vsync_period);
+	if (diff_to_next > vsync_period)
+		return;
+	wakeup_time = ktime_add_ns(cur_time, diff_to_next * NSEC_PER_MSEC);
+	activate_event_timer(mfd->cpu_pm_hdl, wakeup_time);
+}
+
 static DEFINE_SPINLOCK(mdp_lock);
 static int mdp_irq_mask;
 static int mdp_irq_enabled;
@@ -1782,7 +1877,7 @@
 	unsigned long flag;
 	struct mdp_hist_mgmt *mgmt = NULL;
 	int i, ret;
-	int vsync_isr;
+	int vsync_isr, disabled_clocks;
 	/* Ensure all the register write are complete */
 	mb();
 
@@ -1805,19 +1900,25 @@
 	if (mdp_interrupt & MDP_PRIM_RDPTR) {
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		vsync_isr = vsync_cntrl.vsync_irq_enabled;
-		if (!vsync_isr) {
+		disabled_clocks = vsync_cntrl.disabled_clocks;
+		if ((!vsync_isr && !vsync_cntrl.disabled_clocks)
+			|| (!vsync_isr && vsync_cntrl.vsync_dma_enabled)) {
 			mdp_intr_mask &= ~MDP_PRIM_RDPTR;
 			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			mdp_disable_irq_nosync(MDP_VSYNC_TERM);
+			vsync_cntrl.disabled_clocks = 1;
+		} else if (vsync_isr) {
+			vsync_isr_handler();
 		}
+		vsync_cntrl.vsync_dma_enabled = 0;
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-		if (vsync_isr) {
-			vsync_isr_handler();
-		} else {
+		complete(&vsync_cntrl.vsync_comp);
+		if (!vsync_isr && !disabled_clocks)
 			mdp_pipe_ctrl(MDP_CMD_BLOCK,
 				MDP_BLOCK_POWER_OFF, TRUE);
-			complete(&vsync_cntrl.vsync_wait);
-		}
+
+		complete_all(&vsync_cntrl.vsync_wait);
 	}
 
 	/* DMA3 TV-Out Start */
@@ -1870,16 +1971,18 @@
 			if (!vsync_isr) {
 				mdp_intr_mask &= ~LCDC_FRAME_START;
 				outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+				mdp_disable_irq_nosync(MDP_VSYNC_TERM);
+				vsync_cntrl.disabled_clocks = 1;
+			} else {
+				vsync_isr_handler();
 			}
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-			if (vsync_isr) {
-				vsync_isr_handler();
-			} else {
+			if (!vsync_isr)
 				mdp_pipe_ctrl(MDP_CMD_BLOCK,
 					MDP_BLOCK_POWER_OFF, TRUE);
-				complete(&vsync_cntrl.vsync_wait);
-			}
+
+			complete_all(&vsync_cntrl.vsync_wait);
 		}
 
 		/* DMA2 LCD-Out Complete */
@@ -1927,6 +2030,7 @@
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
 			mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF,
 				TRUE);
+			mdp_disable_irq_nosync(MDP_DMA2_TERM);
 			complete(&dma->comp);
 		}
 #endif
@@ -1978,6 +2082,7 @@
 	dma2_data.dmap_busy = FALSE;
 	dma2_data.waiting = FALSE;
 	init_completion(&dma2_data.comp);
+	init_completion(&vsync_cntrl.vsync_comp);
 	init_completion(&dma2_data.dmap_comp);
 	sema_init(&dma2_data.mutex, 1);
 	mutex_init(&dma2_data.ov_mutex);
@@ -2009,8 +2114,9 @@
 	for (i = 0; i < MDP_MAX_BLOCK; i++) {
 		atomic_set(&mdp_block_power_cnt[i], 0);
 	}
-	INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
+	vsync_cntrl.disabled_clocks = 1;
 	init_completion(&vsync_cntrl.vsync_wait);
+	atomic_set(&vsync_cntrl.vsync_resume, 1);
 #ifdef MSM_FB_ENABLE_DBGFS
 	{
 		struct dentry *root;
@@ -2096,7 +2202,9 @@
 
 	pr_debug("%s:+\n", __func__);
 	mdp_histogram_ctrl_all(FALSE);
-
+	atomic_set(&vsync_cntrl.suspend, 1);
+	atomic_set(&vsync_cntrl.vsync_resume, 0);
+	complete_all(&vsync_cntrl.vsync_wait);
 	mdp_clk_ctrl(1);
 	if (mfd->panel.type == MIPI_CMD_PANEL)
 		mdp4_dsi_cmd_off(pdev);
@@ -2127,7 +2235,16 @@
 {
 	/* empty */
 }
+
 #endif
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
 
 static int mdp_on(struct platform_device *pdev)
 {
@@ -2157,10 +2274,26 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	}
 
-	if ((mdp_rev == MDP_REV_303) &&
-			(mfd->panel.type == MIPI_CMD_PANEL))
+	if (mdp_rev == MDP_REV_303 && mfd->panel.type == MIPI_CMD_PANEL) {
+
 		vsync_cntrl.dev = mfd->fbi->dev;
 
+		if (!vsync_cntrl.sysfs_created) {
+			ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
+				&vsync_fs_attr_group);
+			if (ret) {
+				pr_err("%s: sysfs creation failed, ret=%d\n",
+					__func__, ret);
+				return ret;
+			}
+
+			kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
+			pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+			vsync_cntrl.sysfs_created = 1;
+		}
+		atomic_set(&vsync_cntrl.suspend, 0);
+	}
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	ret = panel_next_on(pdev);
@@ -2383,6 +2516,7 @@
 	int rc;
 	resource_size_t  size ;
 	unsigned long flag;
+	u32 frame_rate;
 #ifdef CONFIG_FB_MSM_MDP40
 	int intf, if_no;
 #endif
@@ -2391,6 +2525,7 @@
 #endif
 	static int contSplash_update_done;
 	char *cp;
+	unsigned int mdp_r = 0;
 
 	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
 		mdp_init_pdev = pdev;
@@ -2412,6 +2547,15 @@
 		}
 
 		mdp_rev = mdp_pdata->mdp_rev;
+		if (mdp_rev == MDP_REV_42) {
+			mdp_r = inpdw(MDP_BASE + 0x0);
+			mdp_r = ((mdp_r & 0x30000) >> 16);
+			if (mdp_r == 3) {
+				mdp_rev = MDP_REV_43;
+				mdp_pdata->mdp_rev = MDP_REV_43;
+			}
+		}
+
 		mdp_iommu_split_domain = mdp_pdata->mdp_iommu_split_domain;
 
 		rc = mdp_irq_clk_setup(pdev, mdp_pdata->cont_splash_enabled);
@@ -2434,7 +2578,9 @@
 #ifdef CONFIG_FB_MSM_OVERLAY
 		mdp_hw_cursor_init();
 #endif
-		mdp_clk_ctrl(0);
+
+		if (!(mdp_pdata->cont_splash_enabled))
+			mdp_clk_ctrl(0);
 
 		mdp_resource_initialized = 1;
 		return 0;
@@ -2823,6 +2969,11 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	}
 
+	frame_rate = mdp_get_panel_framerate(mfd);
+	if (frame_rate) {
+		mfd->panel_info.frame_interval = 1000 / frame_rate;
+		mfd->cpu_pm_hdl = add_event_timer(NULL, (void *)mfd);
+	}
 	mdp_clk_ctrl(0);
 
 #ifdef CONFIG_MSM_BUS_SCALING
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 371174c..d939c62 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -94,10 +94,16 @@
 
 struct vsync {
 	ktime_t vsync_time;
+	struct completion vsync_comp;
 	struct device *dev;
 	struct work_struct vsync_work;
 	int vsync_irq_enabled;
+	int vsync_dma_enabled;
+	int disabled_clocks;
 	struct completion vsync_wait;
+	atomic_t suspend;
+	atomic_t vsync_resume;
+	int sysfs_created;
 };
 
 extern struct vsync vsync_cntrl;
@@ -901,6 +907,7 @@
 int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
 	unsigned long srcp0_addr, unsigned long srcp0_size,
 	unsigned long srcp1_addr, unsigned long srcp1_size);
+void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync);
 
 #ifdef CONFIG_FB_MSM_DTV
 void mdp_vid_quant_set(void);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 005e87c..180a18a 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -306,10 +306,16 @@
 	uint32 is_fg;		/* control alpha & color key */
 	uint32 srcp0_addr;	/* interleave, luma */
 	uint32 srcp0_ystride;
+	struct file *srcp0_file;
+	int put0_need;
 	uint32 srcp1_addr;	/* pseudoplanar, chroma plane */
 	uint32 srcp1_ystride;
+	struct file *srcp1_file;
+	int put1_need;
 	uint32 srcp2_addr;	/* planar color 2*/
 	uint32 srcp2_ystride;
+	struct file *srcp2_file;
+	int put2_need;
 	uint32 srcp3_addr;	/* alpha/color 3 */
 	uint32 srcp3_ystride;
 	uint32 fetch_plane;
@@ -349,7 +355,7 @@
 	uint32 ov_cnt;
 	uint32 dmap_cnt;
 	uint32 dmae_cnt;
-	uint32 blt_end;
+	uint32 blt_end;	/* used by mddi only */
 	uint32 blt_ov_koff;
 	uint32 blt_ov_done;
 	uint32 blt_dmap_koff;
@@ -543,12 +549,9 @@
 void mdp4_overlay0_done_dsi_cmd(int cndx);
 void mdp4_primary_rdptr(void);
 void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd);
-int mdp4_overlay_commit(struct fb_info *info, int mixer);
-int mdp4_dsi_video_pipe_commit(void);
-int mdp4_dsi_cmd_pipe_commit(void);
+int mdp4_lcdc_pipe_commit(int cndx, int wait);
+int mdp4_dtv_pipe_commit(int cndx, int wait);
 int mdp4_dsi_cmd_update_cnt(int cndx);
-int mdp4_lcdc_pipe_commit(void);
-int mdp4_dtv_pipe_commit(void);
 void mdp4_dsi_rdptr_init(int cndx);
 void mdp4_dsi_vsync_init(int cndx);
 void mdp4_lcdc_vsync_init(int cndx);
@@ -577,6 +580,7 @@
 int mdp4_overlay_play_wait(struct fb_info *info,
 	struct msmfb_overlay_data *req);
 int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
+int mdp4_overlay_commit(struct fb_info *info, int mixer);
 struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer);
 void mdp4_overlay_dma_commit(int mixer);
 void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe);
@@ -763,6 +767,8 @@
 void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime);
 void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
+int mdp4_dsi_video_pipe_commit(int cndx, int wait);
+int mdp4_dsi_cmd_pipe_commit(int cndx, int wait);
 void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable);
 void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable);
 #ifdef CONFIG_FB_MSM_MDP303
@@ -812,6 +818,14 @@
 			struct mdp4_overlay_pipe *pipe)
 {
 }
+static inline int mdp4_dsi_video_pipe_commit(int cndx, int wait)
+{
+	return 0;
+}
+static inline int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)
+{
+	return 0;
+}
 static inline void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info,
 				int enable)
 {
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 18cf817..8499e3e 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -191,6 +191,19 @@
 	if (pipe == NULL)
 		return;
 
+	if (pipe->flags & MDP_MEMORY_ID_TYPE_FB) {
+		if (pipe->put0_need)
+			fput_light(pipe->srcp0_file, pipe->put0_need);
+		if (pipe->put1_need)
+			fput_light(pipe->srcp1_file, pipe->put1_need);
+		if (pipe->put2_need)
+			fput_light(pipe->srcp2_file, pipe->put2_need);
+
+		pr_debug("%s: ndx=%d flags=%x put=%d\n", __func__,
+			pipe->pipe_ndx, pipe->flags, pipe->put0_need);
+		return;
+	}
+
 	mutex_lock(&iommu_mutex);
 	mixer = pipe->mixer_num;
 	iom = &pipe->iommu;
@@ -735,37 +748,53 @@
 	*luma_off = 0;
 	*chroma_off = 0;
 
-	if (pipe->src_x && (pipe->frame_format ==
+	if ((pipe->src_x || pipe->src_y) && (pipe->frame_format ==
 		MDP4_FRAME_FORMAT_LINEAR)) {
-		src_xy = (pipe->src_y << 16) | pipe->src_x;
-		src_xy &= 0xffff0000;
+		src_xy = 0;
 		outpdw(vg_base + 0x0004, src_xy);	/* MDP_RGB_SRC_XY */
 
 		switch (pipe->src_format) {
 		case MDP_Y_CR_CB_H2V2:
 		case MDP_Y_CR_CB_GH2V2:
 		case MDP_Y_CB_CR_H2V2:
-				*luma_off = pipe->src_x;
-				*chroma_off = pipe->src_x/2;
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x / 2 +
+				((pipe->src_y / 2) * pipe->srcp1_ystride);
 			break;
 
 		case MDP_Y_CBCR_H2V2_TILE:
 		case MDP_Y_CRCB_H2V2_TILE:
 		case MDP_Y_CBCR_H2V2:
 		case MDP_Y_CRCB_H2V2:
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x +
+				((pipe->src_y / 2) * pipe->srcp1_ystride);
+			break;
+
 		case MDP_Y_CRCB_H1V1:
 		case MDP_Y_CBCR_H1V1:
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x +
+				((pipe->src_y * 2) * pipe->srcp1_ystride);
+			break;
+
 		case MDP_Y_CRCB_H2V1:
 		case MDP_Y_CBCR_H2V1:
 		case MDP_Y_CRCB_H1V2:
-			*luma_off = pipe->src_x;
-			*chroma_off = pipe->src_x;
+			*luma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp0_ystride);
+			*chroma_off = pipe->src_x +
+				(pipe->src_y * pipe->srcp1_ystride);
 			break;
 
 		case MDP_YCRYCB_H2V1:
 			if (pipe->src_x & 0x1)
 				pipe->src_x += 1;
-			*luma_off += pipe->src_x * 2;
+			*luma_off += pipe->src_x * 2 +
+				((pipe->src_y * 2) * pipe->srcp0_ystride);
 			break;
 
 		case MDP_ARGB_8888:
@@ -778,7 +807,8 @@
 		case MDP_RGB_888:
 		case MDP_YCBCR_H1V1:
 		case MDP_YCRCB_H1V1:
-			*luma_off = pipe->src_x * pipe->bpp;
+			*luma_off = (pipe->src_x * pipe->bpp) +
+					(pipe->src_y * pipe->srcp0_ystride);
 			break;
 
 		default:
@@ -1619,6 +1649,8 @@
 		data |= stage;
 	}
 
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	mdp_clk_ctrl(1);
 	mdp4_mixer_blend_setup(mixer);
 
 	off = 0;
@@ -1638,7 +1670,6 @@
 				mixer, data, ctrl->flush[mixer], current->pid);
 	}
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	local_irq_save(flags);
 	if (off)
 		outpdw(MDP_BASE + off, data);
@@ -1649,6 +1680,7 @@
 	}
 	local_irq_restore(flags);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	mdp_clk_ctrl(0);
 }
 
 
@@ -1927,7 +1959,7 @@
 	struct mdp4_overlay_pipe *d_pipe;
 	struct mdp4_overlay_pipe *s_pipe;
 	struct blend_cfg *blend;
-	int i, off, ptype, alpha_drop = 0;
+	int i, off, alpha_drop = 0;
 	int d_alpha, s_alpha;
 	unsigned char *overlay_base;
 	uint32 c0, c1, c2, base_premulti;
@@ -1973,7 +2005,8 @@
 		blend->bg_alpha = 0x0ff - s_pipe->alpha;
 		blend->fg_alpha = s_pipe->alpha;
 		blend->co3_sel = 1; /* use fg alpha */
-
+		pr_debug("%s: bg alpha %d, fg alpha %d\n",
+			__func__, blend->bg_alpha, blend->fg_alpha);
 		if (s_pipe->is_fg) {
 			if (s_pipe->alpha == 0xff) {
 				blend->solidfill = 1;
@@ -1989,30 +2022,21 @@
 						MDP4_BLEND_FG_ALPHA_FG_PIXEL;
 				else
 					blend->fg_alpha = 0xff;
+				blend->op |= MDP4_BLEND_BG_INV_ALPHA;
 			} else
 				blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST;
-
-			blend->op |= MDP4_BLEND_BG_INV_ALPHA;
 		} else if (d_alpha) {
-			ptype = mdp4_overlay_format2type(s_pipe->src_format);
-			if (ptype == OVERLAY_TYPE_VIDEO) {
-				blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
-					MDP4_BLEND_FG_INV_ALPHA);
-				if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
-						((i != MDP4_MIXER_STAGE0) ||
-							(!base_premulti)))
-					blend->op |=
-						MDP4_BLEND_BG_ALPHA_BG_PIXEL;
-				else
-					blend->fg_alpha = 0xff;
+			blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+				MDP4_BLEND_FG_INV_ALPHA);
+			if ((!(d_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
+					((i != MDP4_MIXER_STAGE0) ||
+						(!base_premulti)))
+				blend->op |=
+					MDP4_BLEND_BG_ALPHA_BG_PIXEL;
+			else
+				blend->fg_alpha = 0xff;
 
-				blend->co3_sel = 0; /* use bg alpha */
-			} else {
-				/* s_pipe is rgb without alpha */
-				blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
-					    MDP4_BLEND_BG_ALPHA_BG_CONST);
-				blend->bg_alpha = 0;
-			}
+			blend->co3_sel = 0; /* use bg alpha */
 		}
 
 		if (s_pipe->transp != MDP_TRANSP_NOP) {
@@ -2314,6 +2338,18 @@
 		return -ERANGE;
 	}
 
+	if (mdp_rev <= MDP_REV_41) {
+		if ((mdp4_overlay_format2type(req->src.format) ==
+			OVERLAY_TYPE_RGB) &&
+			!(req->flags & MDP_OV_PIPE_SHARE) &&
+			((req->src_rect.w > req->dst_rect.w) ||
+			 (req->src_rect.h > req->dst_rect.h))) {
+			mdp4_stat.err_size++;
+			pr_err("%s: downscale on RGB pipe!\n", __func__);
+			return -EINVAL;
+		}
+	}
+
 	if (mdp_hw_revision == MDP4_REVISION_V1) {
 		/*  non integer down saceling ratio  smaller than 1/4
 		 *  is not supportted
@@ -2924,14 +2960,13 @@
 		if (file == NULL)
 			return -EINVAL;
 
+		pipe->flags |= MDP_MEMORY_ID_TYPE_FB;
 		if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
 			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
 			if (get_fb_phys_info(start, len, fb_num,
 				DISPLAY_SUBSYSTEM_ID)) {
 				ret = -1;
 			} else {
-				pr_warn("%s: mdp4_overlay play with FB memory\n",
-							 __func__);
 				*srcp_file = file;
 				*p_need = put_needed;
 			}
@@ -3289,11 +3324,8 @@
 	struct mdp4_overlay_pipe *pipe;
 	ulong start, addr;
 	ulong len = 0;
-	struct file *srcp0_file = NULL;
-	struct file *srcp1_file = NULL, *srcp2_file = NULL;
 	struct ion_handle *srcp0_ihdl = NULL;
 	struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL;
-	int ps0_need, p_need;
 	uint32_t overlay_version = 0;
 	int ret = 0;
 
@@ -3318,8 +3350,8 @@
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	img = &req->data;
-	get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
-		&ps0_need, &srcp0_ihdl);
+	get_img(img, info, pipe, 0, &start, &len, &pipe->srcp0_file,
+		&pipe->put0_need, &srcp0_ihdl);
 	if (len == 0) {
 		pr_err("%s: pmem Error\n", __func__);
 		ret = -1;
@@ -3341,8 +3373,9 @@
 	if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) {
 		if (overlay_version > 0) {
 			img = &req->plane1_data;
-			get_img(img, info, pipe, 1, &start, &len, &srcp1_file,
-				&p_need, &srcp1_ihdl);
+			get_img(img, info, pipe, 1, &start, &len,
+				&pipe->srcp1_file, &pipe->put1_need,
+				&srcp1_ihdl);
 			if (len == 0) {
 				pr_err("%s: Error to get plane1\n", __func__);
 				ret = -EINVAL;
@@ -3373,8 +3406,9 @@
 	} else if (pipe->fetch_plane == OVERLAY_PLANE_PLANAR) {
 		if (overlay_version > 0) {
 			img = &req->plane1_data;
-			get_img(img, info, pipe, 1, &start, &len, &srcp1_file,
-				&p_need, &srcp1_ihdl);
+			get_img(img, info, pipe, 1, &start, &len,
+				&pipe->srcp1_file, &pipe->put1_need,
+				&srcp1_ihdl);
 			if (len == 0) {
 				pr_err("%s: Error to get plane1\n", __func__);
 				ret = -EINVAL;
@@ -3383,8 +3417,9 @@
 			pipe->srcp1_addr = start + img->offset;
 
 			img = &req->plane2_data;
-			get_img(img, info, pipe, 2, &start, &len, &srcp2_file,
-				&p_need, &srcp2_ihdl);
+			get_img(img, info, pipe, 2, &start, &len,
+				&pipe->srcp2_file, &pipe->put2_need,
+				&srcp2_ihdl);
 			if (len == 0) {
 				pr_err("%s: Error to get plane2\n", __func__);
 				ret = -EINVAL;
@@ -3433,8 +3468,7 @@
 		if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
 			/* cndx = 0 */
 			mdp4_dsi_cmd_pipe_queue(0, pipe);
-		}
-		if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+		} else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
 			/* cndx = 0 */
 			mdp4_dsi_video_pipe_queue(0, pipe);
 		} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
@@ -3482,20 +3516,49 @@
 end:
 	mutex_unlock(&mfd->dma->ov_mutex);
 
-#ifdef CONFIG_ANDROID_PMEM
-	if (srcp0_file)
-		put_pmem_file(srcp0_file);
-	if (srcp1_file)
-		put_pmem_file(srcp1_file);
-	if (srcp2_file)
-		put_pmem_file(srcp2_file);
-#endif
-	/* only source may use frame buffer */
-	if (img->flags & MDP_MEMORY_ID_TYPE_FB)
-		fput_light(srcp0_file, ps0_need);
 	return ret;
 }
 
+int mdp4_overlay_commit(struct fb_info *info, int mixer)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if (mfd == NULL)
+		return -ENODEV;
+
+	if (!mfd->panel_power_on) /* suspended */
+		return -EINVAL;
+
+	if (mixer >= MDP4_MIXER_MAX)
+		return -EPERM;
+
+	mutex_lock(&mfd->dma->ov_mutex);
+
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
+
+	if (mixer == MDP4_MIXER0) {
+		if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+			/* cndx = 0 */
+			mdp4_dsi_cmd_pipe_commit(0, 1);
+		} else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+			/* cndx = 0 */
+			mdp4_dsi_video_pipe_commit(0, 1);
+		} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+			/* cndx = 0 */
+			mdp4_lcdc_pipe_commit(0, 1);
+		}
+	} else if (mixer == MDP4_MIXER1) {
+		if (ctrl->panel_mode & MDP4_PANEL_DTV)
+			mdp4_dtv_pipe_commit(0, 1);
+	}
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
+
+	mutex_unlock(&mfd->dma->ov_mutex);
+
+	return 0;
+}
+
 struct msm_iommu_ctx {
 	char *name;
 	int  domain;
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index e67b244..90c3da9 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -184,6 +184,8 @@
 	} else {
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 	}
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
+
 	mdp4_overlay_mdp_perf_req(pipe, mfd);
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 	mdp4_overlay_rgb_setup(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 3320d11..ecdd567 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -39,7 +39,7 @@
 static int vsync_start_y_adjust = 4;
 
 #define MAX_CONTROLLER	1
-#define VSYNC_EXPIRE_TICK 8
+#define VSYNC_EXPIRE_TICK 4
 
 static struct vsycn_ctrl {
 	struct device *dev;
@@ -54,11 +54,12 @@
 	uint32 rdptr_intr_tot;
 	uint32 rdptr_sirq_tot;
 	atomic_t suspend;
+	atomic_t vsync_resume;
 	int wait_vsync_cnt;
 	int blt_change;
 	int blt_free;
 	int blt_end;
-	int uevent;
+	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
 	struct completion dmap_comp;
@@ -72,7 +73,6 @@
 	int clk_control;
 	int new_update;
 	ktime_t vsync_time;
-	struct work_struct vsync_work;
 	struct work_struct clk_work;
 } vsync_ctrl_db[MAX_CONTROLLER];
 
@@ -250,7 +250,7 @@
 
 static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe);
 
-int mdp4_dsi_cmd_pipe_commit(void)
+int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)
 {
 	int  i, undx;
 	int mixer = 0;
@@ -377,6 +377,12 @@
 
 	mdp4_stat.overlay_commit[pipe->mixer_num]++;
 
+	if (wait) {
+		long long tick;
+
+		mdp4_dsi_cmd_wait4vsync(cndx, &tick);
+	}
+
 	return cnt;
 }
 
@@ -384,7 +390,6 @@
 
 void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable)
 {
-	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct vsycn_ctrl *vctrl;
 	unsigned long flags;
 	int clk_set_on = 0;
@@ -415,24 +420,23 @@
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
 		vctrl->clk_control = 0;
 		vctrl->expire_tick = 0;
-		vctrl->uevent = 1;
 		vctrl->new_update = 1;
 		if (clk_set_on) {
 			vsync_irq_enable(INTR_PRIMARY_RDPTR,
 						MDP_PRIM_RDPTR_TERM);
 		}
 		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-
-		mdp4_overlay_update_dsi_cmd(mfd);
 	} else {
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
 		vctrl->clk_control = 1;
-		vctrl->uevent = 0;
 		if (vctrl->clk_enabled)
 			vctrl->expire_tick = VSYNC_EXPIRE_TICK;
 		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 	}
 	mutex_unlock(&vctrl->update_lock);
+
+	if (vctrl->vsync_enabled &&  atomic_read(&vctrl->suspend) == 0)
+		atomic_set(&vctrl->vsync_resume, 1);
 }
 
 void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -515,13 +519,9 @@
 	vctrl->vsync_time = ktime_get();
 
 	spin_lock(&vctrl->spin_lock);
-	if (vctrl->uevent)
-		schedule_work(&vctrl->vsync_work);
 
-	if (vctrl->wait_vsync_cnt) {
-		complete(&vctrl->vsync_comp);
-		vctrl->wait_vsync_cnt = 0;
-	}
+	complete_all(&vctrl->vsync_comp);
+	vctrl->wait_vsync_cnt = 0;
 
 	if (vctrl->expire_tick) {
 		vctrl->expire_tick--;
@@ -539,6 +539,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	 /* blt enabled */
 	spin_lock(&vctrl->spin_lock);
@@ -578,6 +580,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	spin_lock(&vctrl->spin_lock);
 	vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
@@ -636,21 +640,35 @@
 	mutex_unlock(&vctrl->update_lock);
 }
 
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct vsycn_ctrl *vctrl =
-		container_of(work, typeof(*vctrl), vsync_work);
-	char buf[64];
-	char *envp[2];
+	int cndx;
+	struct vsycn_ctrl *vctrl;
+	ssize_t ret = 0;
+	unsigned long flags;
 
-	snprintf(buf, sizeof(buf), "VSYNC=%llu",
+	cndx = 0;
+	vctrl = &vsync_ctrl_db[0];
+
+	if (atomic_read(&vctrl->suspend) > 0 ||
+		atomic_read(&vctrl->vsync_resume) == 0)
+		return 0;
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (vctrl->wait_vsync_cnt == 0)
+		INIT_COMPLETION(vctrl->vsync_comp);
+	vctrl->wait_vsync_cnt++;
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+	wait_for_completion(&vctrl->vsync_comp);
+
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
 			ktime_to_ns(vctrl->vsync_time));
-	envp[0] = buf;
-	envp[1] = NULL;
-	kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
 }
 
-
 void mdp4_dsi_rdptr_init(int cndx)
 {
 	struct vsycn_ctrl *vctrl;
@@ -671,7 +689,7 @@
 	init_completion(&vctrl->dmap_comp);
 	init_completion(&vctrl->vsync_comp);
 	spin_lock_init(&vctrl->spin_lock);
-	INIT_WORK(&vctrl->vsync_work, send_vsync_work);
+	atomic_set(&vctrl->vsync_resume, 1);
 	INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
 }
 
@@ -952,6 +970,14 @@
 	mdp4_dsi_cmd_do_blt(mfd, req->enable);
 }
 
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
 int mdp4_dsi_cmd_on(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -976,6 +1002,19 @@
 	atomic_set(&vctrl->suspend, 0);
 	pr_debug("%s-:\n", __func__);
 
+	if (!vctrl->sysfs_created) {
+		ret = sysfs_create_group(&vctrl->dev->kobj,
+			&vsync_fs_attr_group);
+		if (ret) {
+			pr_err("%s: sysfs group creation failed, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+		vctrl->sysfs_created = 1;
+	}
 
 	return ret;
 }
@@ -987,6 +1026,8 @@
 	struct msm_fb_data_type *mfd;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	struct vsync_update *vp;
+	int undx;
 
 	pr_debug("%s+:\n", __func__);
 
@@ -1000,6 +1041,9 @@
 	}
 
 	atomic_set(&vctrl->suspend, 1);
+	atomic_set(&vctrl->vsync_resume, 0);
+
+	complete_all(&vctrl->vsync_comp);
 
 	/* sanity check, free pipes besides base layer */
 	mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -1016,11 +1060,20 @@
 		mdp_clk_ctrl(0);
 	}
 
+	undx =  vctrl->update_ndx;
+	vp = &vctrl->vlist[undx];
+	if (vp->update_cnt) {
+		/*
+		 * pipe's iommu will be freed at next overlay play
+		 * and iommu_drop statistic will be increased by one
+		 */
+		vp->update_cnt = 0;     /* empty queue */
+	}
+
 	vctrl->clk_enabled = 0;
 	vctrl->vsync_enabled = 0;
 	vctrl->clk_control = 0;
 	vctrl->expire_tick = 0;
-	vctrl->uevent = 0;
 
 	vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
 
@@ -1068,7 +1121,7 @@
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
 	unsigned long flags;
-	long long xx;
+	long long tick;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
@@ -1109,10 +1162,10 @@
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mutex_lock(&mfd->dma->ov_mutex);
-	mdp4_dsi_cmd_pipe_commit();
+	mdp4_dsi_cmd_pipe_commit(cndx, 0);
 	mutex_unlock(&mfd->dma->ov_mutex);
 
-	mdp4_dsi_cmd_wait4vsync(0, &xx);
+	mdp4_dsi_cmd_wait4vsync(cndx, &tick);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 2d21929..6aa101f 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -52,10 +52,11 @@
 	int ov_koff;
 	int ov_done;
 	atomic_t suspend;
+	atomic_t vsync_resume;
 	int wait_vsync_cnt;
 	int blt_change;
 	int blt_free;
-	int fake_vsync;
+	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
 	struct completion dmap_comp;
@@ -66,7 +67,6 @@
 	struct vsync_update vlist[2];
 	int vsync_irq_enabled;
 	ktime_t vsync_time;
-	struct work_struct vsync_work;
 } vsync_ctrl_db[MAX_CONTROLLER];
 
 static void vsync_irq_enable(int intr, int term)
@@ -147,7 +147,7 @@
 static void mdp4_dsi_video_wait4dmap(int cndx);
 static void mdp4_dsi_video_wait4ov(int cndx);
 
-int mdp4_dsi_video_pipe_commit(void)
+int mdp4_dsi_video_pipe_commit(int cndx, int wait)
 {
 
 	int  i, undx;
@@ -159,7 +159,7 @@
 	unsigned long flags;
 	int cnt = 0;
 
-	vctrl = &vsync_ctrl_db[0];
+	vctrl = &vsync_ctrl_db[cndx];
 
 	mutex_lock(&vctrl->update_lock);
 	undx =  vctrl->update_ndx;
@@ -253,6 +253,13 @@
 
 	mdp4_stat.overlay_commit[pipe->mixer_num]++;
 
+	if (wait) {
+		if (pipe->ov_blt_addr)
+			mdp4_dsi_video_wait4ov(cndx);
+		else
+			mdp4_dsi_video_wait4dmap(cndx);
+	}
+
 	return cnt;
 }
 
@@ -263,11 +270,6 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 
-	if (vctrl->fake_vsync) {
-		vctrl->fake_vsync = 0;
-		schedule_work(&vctrl->vsync_work);
-	}
-
 	if (vctrl->vsync_irq_enabled == enable)
 		return;
 
@@ -279,6 +281,9 @@
 		vsync_irq_enable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
 	else
 		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+
+	if (vctrl->vsync_irq_enabled &&  atomic_read(&vctrl->suspend) == 0)
+		atomic_set(&vctrl->vsync_resume, 1);
 }
 
 void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime)
@@ -350,7 +355,6 @@
 	vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 	mdp4_dsi_video_wait4dmap(cndx);
-	vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
 }
 
 
@@ -371,18 +375,32 @@
 	wait_for_completion(&vctrl->ov_comp);
 }
 
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+	struct device_attribute *attr, char *buf)
 {
-	struct vsycn_ctrl *vctrl =
-			container_of(work, typeof(*vctrl), vsync_work);
-	char buf[64];
-	char *envp[2];
+	int cndx;
+	struct vsycn_ctrl *vctrl;
+	ssize_t ret = 0;
+	unsigned long flags;
 
-	snprintf(buf, sizeof(buf), "VSYNC=%llu",
+	cndx = 0;
+	vctrl = &vsync_ctrl_db[0];
+
+	if (atomic_read(&vctrl->suspend) > 0 ||
+		atomic_read(&vctrl->vsync_resume) == 0)
+		return 0;
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (vctrl->wait_vsync_cnt == 0)
+		INIT_COMPLETION(vctrl->vsync_comp);
+	vctrl->wait_vsync_cnt++;
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	wait_for_completion(&vctrl->vsync_comp);
+
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
 			ktime_to_ns(vctrl->vsync_time));
-	envp[0] = buf;
-	envp[1] = NULL;
-	kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
 }
 
 void mdp4_dsi_vsync_init(int cndx)
@@ -407,8 +425,8 @@
 	init_completion(&vctrl->dmap_comp);
 	init_completion(&vctrl->ov_comp);
 	atomic_set(&vctrl->suspend, 0);
+	atomic_set(&vctrl->vsync_resume, 1);
 	spin_lock_init(&vctrl->spin_lock);
-	INIT_WORK(&vctrl->vsync_work, send_vsync_work);
 }
 
 void mdp4_dsi_video_base_swap(int cndx, struct mdp4_overlay_pipe *pipe)
@@ -424,6 +442,16 @@
 	vctrl->base_pipe = pipe;
 }
 
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
 int mdp4_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -478,7 +506,6 @@
 
 	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
-	vctrl->fake_vsync = 1;
 
 	/* mdp clock on */
 	mdp_clk_ctrl(1);
@@ -522,6 +549,9 @@
 		mdp4_dsi_video_wait4dmap_done(0);
 		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 		mipi_dsi_controller_cfg(0);
+		/* Clks are enabled in probe.
+		   Disabling clocks now */
+		mdp_clk_ctrl(0);
 	}
 
 	pipe->src_height = fbi->var.yres;
@@ -634,6 +664,21 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	mdp_histogram_ctrl_all(TRUE);
+
+	if (!vctrl->sysfs_created) {
+		ret = sysfs_create_group(&vctrl->dev->kobj,
+			&vsync_fs_attr_group);
+		if (ret) {
+			pr_err("%s: sysfs group creation failed, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+		vctrl->sysfs_created = 1;
+	}
+
 	return ret;
 }
 
@@ -644,17 +689,21 @@
 	struct msm_fb_data_type *mfd;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	struct vsync_update *vp;
 	unsigned long flags;
-	int need_wait = 0;
+	int undx, need_wait = 0;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
 	atomic_set(&vctrl->suspend, 1);
+	atomic_set(&vctrl->vsync_resume, 0);
 
 	msleep(20);	/* >= 17 ms */
 
+	complete_all(&vctrl->vsync_comp);
+
 	if (pipe->ov_blt_addr) {
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
 		if (vctrl->ov_koff != vctrl->ov_done)
@@ -670,6 +719,21 @@
 
 	dsi_video_enabled = 0;
 
+	if (vctrl->vsync_irq_enabled) {
+		vctrl->vsync_irq_enabled = 0;
+		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+	}
+
+	undx =  vctrl->update_ndx;
+	vp = &vctrl->vlist[undx];
+	if (vp->update_cnt) {
+		/*
+		 * pipe's iommu will be freed at next overlay play
+		 * and iommu_drop statistic will be increased by one
+		 */
+		vp->update_cnt = 0;     /* empty queue */
+	}
+
 	if (pipe) {
 		/* sanity check, free pipes besides base layer */
 		mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -691,8 +755,6 @@
 		}
 	}
 
-	vctrl->fake_vsync = 1;
-
 	/* mdp clock off */
 	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -857,7 +919,6 @@
 	vctrl = &vsync_ctrl_db[cndx];
 	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
 	vctrl->vsync_time = ktime_get();
-	schedule_work(&vctrl->vsync_work);
 
 	spin_lock(&vctrl->spin_lock);
 	if (vctrl->wait_vsync_cnt) {
@@ -881,6 +942,8 @@
 	}
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	spin_lock(&vctrl->spin_lock);
 	vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
@@ -916,6 +979,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	spin_lock(&vctrl->spin_lock);
 	vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
@@ -1028,16 +1093,17 @@
 		mdp4_dsi_video_pipe_queue(0, pipe);
 	}
 
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mutex_lock(&mfd->dma->ov_mutex);
-	mdp4_dsi_video_pipe_commit();
+	mdp4_dsi_video_pipe_commit(cndx, 0);
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	if (pipe->ov_blt_addr)
-		mdp4_dsi_video_wait4ov(0);
+		mdp4_dsi_video_wait4ov(cndx);
 	else
-		mdp4_dsi_video_wait4dmap(0);
+		mdp4_dsi_video_wait4dmap(cndx);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f01543b..21e5d1d 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -29,6 +29,7 @@
 
 #include "mdp.h"
 #include "msm_fb.h"
+#include "hdmi_msm.h"
 #include "mdp4.h"
 
 #define DTV_BASE	0xD0000
@@ -70,10 +71,11 @@
 	int update_ndx;
 	int dmae_intr_cnt;
 	atomic_t suspend;
+	atomic_t vsync_resume;
 	int dmae_wait_cnt;
 	int wait_vsync_cnt;
 	int blt_change;
-	int fake_vsync;
+	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
 	struct completion dmae_comp;
@@ -83,7 +85,6 @@
 	struct vsync_update vlist[2];
 	int vsync_irq_enabled;
 	ktime_t vsync_time;
-	struct work_struct vsync_work;
 } vsync_ctrl_db[MAX_CONTROLLER];
 
 static void vsync_irq_enable(int intr, int term)
@@ -164,7 +165,7 @@
 static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
 static void mdp4_dtv_wait4dmae(int cndx);
 
-int mdp4_dtv_pipe_commit(void)
+int mdp4_dtv_pipe_commit(int cndx, int wait)
 {
 
 	int  i, undx;
@@ -176,7 +177,7 @@
 	unsigned long flags;
 	int cnt = 0;
 
-	vctrl = &vsync_ctrl_db[0];
+	vctrl = &vsync_ctrl_db[cndx];
 	mutex_lock(&vctrl->update_lock);
 	undx =  vctrl->update_ndx;
 	vp = &vctrl->vlist[undx];
@@ -235,6 +236,9 @@
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 	mdp4_stat.overlay_commit[pipe->mixer_num]++;
 
+	if (wait)
+		mdp4_dtv_wait4dmae(cndx);
+
 	return cnt;
 }
 
@@ -245,10 +249,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 
-	if (vctrl->fake_vsync) {
-		vctrl->fake_vsync = 0;
-		schedule_work(&vctrl->vsync_work);
-	}
+	if (!external_common_state->hpd_state)
+		complete_all(&vctrl->vsync_comp);
 
 	if (vctrl->vsync_irq_enabled == enable)
 		return;
@@ -261,6 +263,9 @@
 		vsync_irq_enable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
 	else
 		vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
+
+	if (vctrl->vsync_irq_enabled &&  atomic_read(&vctrl->suspend) == 0)
+		atomic_set(&vctrl->vsync_resume, 1);
 }
 
 void mdp4_dtv_wait4vsync(int cndx, long long *vtime)
@@ -310,20 +315,34 @@
 	wait_for_completion(&vctrl->dmae_comp);
 }
 
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct vsycn_ctrl *vctrl =
-		container_of(work, typeof(*vctrl), vsync_work);
-	char buf[64];
-	char *envp[2];
+	int cndx;
+	struct vsycn_ctrl *vctrl;
+	ssize_t ret = 0;
+	unsigned long flags;
 
-	snprintf(buf, sizeof(buf), "VSYNC=%llu",
+	cndx = 0;
+	vctrl = &vsync_ctrl_db[0];
+
+	if (atomic_read(&vctrl->suspend) > 0 ||
+		!external_common_state->hpd_state ||
+		atomic_read(&vctrl->vsync_resume) == 0)
+		return 0;
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (vctrl->wait_vsync_cnt == 0)
+		INIT_COMPLETION(vctrl->vsync_comp);
+	vctrl->wait_vsync_cnt++;
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	wait_for_completion(&vctrl->vsync_comp);
+
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
 			ktime_to_ns(vctrl->vsync_time));
-	envp[0] = buf;
-	envp[1] = NULL;
-	kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
 }
-
 void mdp4_dtv_vsync_init(int cndx)
 {
 	struct vsycn_ctrl *vctrl;
@@ -346,8 +365,8 @@
 	init_completion(&vctrl->ov_comp);
 	init_completion(&vctrl->dmae_comp);
 	atomic_set(&vctrl->suspend, 0);
+	atomic_set(&vctrl->vsync_resume, 1);
 	spin_lock_init(&vctrl->spin_lock);
-	INIT_WORK(&vctrl->vsync_work, send_vsync_work);
 }
 
 static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
@@ -506,6 +525,15 @@
 	return 0;
 }
 
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
+
 int mdp4_dtv_on(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
@@ -524,7 +552,6 @@
 		return -EINVAL;
 
 	vctrl->dev = mfd->fbi->dev;
-	vctrl->fake_vsync = 1;
 
 	mdp_footswitch_ctrl(TRUE);
 	/* Mdp clock enable */
@@ -547,6 +574,19 @@
 
 	atomic_set(&vctrl->suspend, 0);
 
+	if (!vctrl->sysfs_created) {
+		ret = sysfs_create_group(&vctrl->dev->kobj,
+			&vsync_fs_attr_group);
+		if (ret) {
+			pr_err("%s: sysfs group creation failed, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+		vctrl->sysfs_created = 1;
+	}
 	pr_info("%s:\n", __func__);
 
 	return ret;
@@ -557,17 +597,24 @@
 	struct msm_fb_data_type *mfd;
 	int ret = 0;
 	int cndx = 0;
+	int undx;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	struct vsync_update *vp;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
 	vctrl = &vsync_ctrl_db[cndx];
 
 	atomic_set(&vctrl->suspend, 1);
+	atomic_set(&vctrl->vsync_resume, 0);
 
-	while (vctrl->wait_vsync_cnt)
-		msleep(20);	/* >= 17 ms */
+	if (vctrl->vsync_irq_enabled) {
+		while (vctrl->wait_vsync_cnt)
+			msleep(20);     /* >= 17 ms */
+	}
+
+	complete_all(&vctrl->vsync_comp);
 
 	pipe = vctrl->base_pipe;
 	if (pipe != NULL) {
@@ -594,9 +641,23 @@
 
 	mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
 
+	if (vctrl->vsync_irq_enabled) {
+		vctrl->vsync_irq_enabled = 0;
+		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+	}
+
+	undx =  vctrl->update_ndx;
+	vp = &vctrl->vlist[undx];
+	if (vp->update_cnt) {
+		/*
+		 * pipe's iommu will be freed at next overlay play
+		 * and iommu_drop statistic will be increased by one
+		 */
+		vp->update_cnt = 0;     /* empty queue */
+	}
+
 	ret = panel_next_off(pdev);
 	mdp_footswitch_ctrl(FALSE);
-	vctrl->fake_vsync = 1;
 
 	/* Mdp clock disable */
 	mdp_clk_ctrl(0);
@@ -795,7 +856,6 @@
 	vctrl = &vsync_ctrl_db[cndx];
 	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
 	vctrl->vsync_time = ktime_get();
-	schedule_work(&vctrl->vsync_work);
 
 	spin_lock(&vctrl->spin_lock);
 	if (vctrl->wait_vsync_cnt) {
@@ -822,6 +882,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
 
 	spin_lock(&vctrl->spin_lock);
@@ -862,6 +924,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	spin_lock(&vctrl->spin_lock);
 	if (pipe->ov_blt_addr == 0) {
@@ -1011,10 +1075,11 @@
 		pipe->srcp0_addr = (uint32)mfd->ibuf.buf;
 		mdp4_dtv_pipe_queue(0, pipe);
 	}
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
 
 	mutex_lock(&mfd->dma->ov_mutex);
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
-	mdp4_dtv_pipe_commit();
+	mdp4_dtv_pipe_commit(cndx, 0);
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index bc8ded5..1f5136f 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -53,10 +53,11 @@
 	int ov_koff;
 	int ov_done;
 	atomic_t suspend;
+	atomic_t vsync_resume;
 	int wait_vsync_cnt;
 	int blt_change;
 	int blt_free;
-	int fake_vsync;
+	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
 	struct completion dmap_comp;
@@ -67,7 +68,6 @@
 	struct vsync_update vlist[2];
 	int vsync_irq_enabled;
 	ktime_t vsync_time;
-	struct work_struct vsync_work;
 } vsync_ctrl_db[MAX_CONTROLLER];
 
 
@@ -152,7 +152,7 @@
 static void mdp4_lcdc_wait4dmap(int cndx);
 static void mdp4_lcdc_wait4ov(int cndx);
 
-int mdp4_lcdc_pipe_commit(void)
+int mdp4_lcdc_pipe_commit(int cndx, int wait)
 {
 
 	int  i, undx;
@@ -164,7 +164,7 @@
 	unsigned long flags;
 	int cnt = 0;
 
-	vctrl = &vsync_ctrl_db[0];
+	vctrl = &vsync_ctrl_db[cndx];
 
 	mutex_lock(&vctrl->update_lock);
 	undx =  vctrl->update_ndx;
@@ -257,6 +257,13 @@
 
 	mdp4_stat.overlay_commit[pipe->mixer_num]++;
 
+	if (wait) {
+		if (pipe->ov_blt_addr)
+			mdp4_lcdc_wait4ov(cndx);
+		else
+			mdp4_lcdc_wait4dmap(cndx);
+	}
+
 	return cnt;
 }
 
@@ -267,11 +274,6 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 
-	if (vctrl->fake_vsync) {
-		vctrl->fake_vsync = 0;
-		schedule_work(&vctrl->vsync_work);
-	}
-
 	if (vctrl->vsync_irq_enabled == enable)
 		return;
 
@@ -283,6 +285,9 @@
 		vsync_irq_enable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
 	else
 		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+
+	if (vctrl->vsync_irq_enabled &&  atomic_read(&vctrl->suspend) == 0)
+		atomic_set(&vctrl->vsync_resume, 1);
 }
 
 void mdp4_lcdc_wait4vsync(int cndx, long long *vtime)
@@ -354,18 +359,32 @@
 	wait_for_completion(&vctrl->ov_comp);
 }
 
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct vsycn_ctrl *vctrl =
-		container_of(work, typeof(*vctrl), vsync_work);
-	char buf[64];
-	char *envp[2];
+	int cndx;
+	struct vsycn_ctrl *vctrl;
+	ssize_t ret = 0;
+	unsigned long flags;
 
-	snprintf(buf, sizeof(buf), "VSYNC=%llu",
-				ktime_to_ns(vctrl->vsync_time));
-	envp[0] = buf;
-	envp[1] = NULL;
-	kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+	cndx = 0;
+	vctrl = &vsync_ctrl_db[0];
+
+	if (atomic_read(&vctrl->suspend) > 0 ||
+		atomic_read(&vctrl->vsync_resume) == 0)
+		return 0;
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (vctrl->wait_vsync_cnt == 0)
+		INIT_COMPLETION(vctrl->vsync_comp);
+	vctrl->wait_vsync_cnt++;
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	wait_for_completion(&vctrl->vsync_comp);
+
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+			ktime_to_ns(vctrl->vsync_time));
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
 }
 
 void mdp4_lcdc_vsync_init(int cndx)
@@ -390,8 +409,8 @@
 	init_completion(&vctrl->dmap_comp);
 	init_completion(&vctrl->ov_comp);
 	atomic_set(&vctrl->suspend, 0);
+	atomic_set(&vctrl->vsync_resume, 1);
 	spin_lock_init(&vctrl->spin_lock);
-	INIT_WORK(&vctrl->vsync_work, send_vsync_work);
 }
 
 void mdp4_lcdc_base_swap(int cndx, struct mdp4_overlay_pipe *pipe)
@@ -407,6 +426,15 @@
 	vctrl->base_pipe = pipe;
 }
 
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
+
 int mdp4_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -461,7 +489,6 @@
 
 	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
-	vctrl->fake_vsync = 1;
 
 	/* mdp clock on */
 	mdp_clk_ctrl(1);
@@ -621,6 +648,21 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	mdp_histogram_ctrl_all(TRUE);
+
+	if (!vctrl->sysfs_created) {
+		ret = sysfs_create_group(&vctrl->dev->kobj,
+			&vsync_fs_attr_group);
+		if (ret) {
+			pr_err("%s: sysfs group creation failed, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+		vctrl->sysfs_created = 1;
+	}
+
 	return ret;
 }
 
@@ -631,17 +673,21 @@
 	struct msm_fb_data_type *mfd;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	struct vsync_update *vp;
 	unsigned long flags;
-	int need_wait = 0;
+	int undx, need_wait = 0;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
 	atomic_set(&vctrl->suspend, 1);
+	atomic_set(&vctrl->vsync_resume, 0);
 
 	msleep(20);	/* >= 17 ms */
 
+	complete_all(&vctrl->vsync_comp);
+
 	if (pipe->ov_blt_addr) {
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
 		if (vctrl->ov_koff != vctrl->ov_done)
@@ -657,6 +703,21 @@
 
 	lcdc_enabled = 0;
 
+	if (vctrl->vsync_irq_enabled) {
+		vctrl->vsync_irq_enabled = 0;
+		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+	}
+
+	undx =  vctrl->update_ndx;
+	vp = &vctrl->vlist[undx];
+	if (vp->update_cnt) {
+		/*
+		 * pipe's iommu will be freed at next overlay play
+		 * and iommu_drop statistic will be increased by one
+		 */
+		vp->update_cnt = 0;     /* empty queue */
+	}
+
 	if (pipe) {
 		/* sanity check, free pipes besides base layer */
 		mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -678,8 +739,6 @@
 		}
 	}
 
-	vctrl->fake_vsync = 1;
-
 	/* MDP clock disable */
 	mdp_clk_ctrl(0);
 	mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -746,7 +805,6 @@
 	vctrl = &vsync_ctrl_db[cndx];
 	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
 	vctrl->vsync_time = ktime_get();
-	schedule_work(&vctrl->vsync_work);
 
 	spin_lock(&vctrl->spin_lock);
 	if (vctrl->wait_vsync_cnt) {
@@ -771,6 +829,8 @@
 	}
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	spin_lock(&vctrl->spin_lock);
 	vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
@@ -809,6 +869,8 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
+	if (pipe == NULL)
+		return;
 
 	spin_lock(&vctrl->spin_lock);
 	vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
@@ -917,17 +979,18 @@
 
 		mdp4_lcdc_pipe_queue(0, pipe);
 	}
+	mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mutex_lock(&mfd->dma->ov_mutex);
-	mdp4_lcdc_pipe_commit();
+	mdp4_lcdc_pipe_commit(cndx, 0);
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	if (pipe->ov_blt_addr)
-		mdp4_lcdc_wait4ov(0);
+		mdp4_lcdc_wait4ov(cndx);
 	else
-		mdp4_lcdc_wait4dmap(0);
+		mdp4_lcdc_wait4dmap(cndx);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 80ef22a..87921e6 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -110,21 +110,22 @@
 	.csc_data = {
 			(0),
 			{
-				0x0200, 0x0000, 0x0000,
-				0x0000, 0x0200, 0x0000,
-				0x0000, 0x0000, 0x0200,
+				0x0083, 0x0102, 0x0032,
+				0x1fb5, 0x1f6c, 0x00e1,
+				0x00e1, 0x1f45, 0x1fdc,
 			},
 			{
 				0x0, 0x0, 0x0,
 			},
 			{
-				0, 0, 0,
+				0x0010, 0x0080, 0x0080,
 			},
 			{
 				0, 0xff, 0, 0xff, 0, 0xff,
 			},
 			{
-				0, 0xff, 0, 0xff, 0, 0xff,
+				0x0010, 0x00eb, 0x0010,
+				0x00f0, 0x0010, 0x00f0,
 			},
 		},
 	},
@@ -133,21 +134,22 @@
 	.csc_data = {
 			(0),
 			{
-				0x0200, 0x0000, 0x0000,
-				0x0000, 0x0200, 0x0000,
-				0x0000, 0x0000, 0x0200,
+				0x0083, 0x0102, 0x0032,
+				0x1fb5, 0x1f6c, 0x00e1,
+				0x00e1, 0x1f45, 0x1fdc,
 			},
 			{
 				0x0, 0x0, 0x0,
 			},
 			{
-				0, 0, 0,
+				0x0010, 0x0080, 0x0080,
 			},
 			{
 				0, 0xff, 0, 0xff, 0, 0xff,
 			},
 			{
-				0, 0xff, 0, 0xff, 0, 0xff,
+				0x0010, 0x00eb, 0x0010,
+				0x00f0, 0x0010, 0x00f0,
 			},
 		},
 	},
@@ -176,7 +178,6 @@
 	},
 };
 
-
 unsigned is_mdp4_hw_reset(void)
 {
 	unsigned hw_reset = 0;
@@ -2138,7 +2139,7 @@
 		base = 0x1A000;
 		break;
 	case MDP_BLOCK_OVERLAY_2:
-		base = (mdp_rev >= MDP_REV_44) ? 0x8A000 : 0x0;
+		base = (mdp_rev >= MDP_REV_43) ? 0x8A000 : 0x0;
 		break;
 	case MDP_BLOCK_VG_1:
 		base = 0x24000;
@@ -2658,7 +2659,7 @@
 		break;
 
 	case MDP_BLOCK_OVERLAY_2:
-		valid = (mdp_rev >= MDP_REV_44) ? 1 : 0;
+		valid = (mdp_rev >= MDP_REV_43) ? 1 : 0;
 		break;
 
 	default:
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index 4b76e72..4d4b05f 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -482,10 +482,22 @@
 #endif
 {
 	unsigned long flag;
+	static int first_vsync;
+	int need_wait = 0;
 
 	down(&mfd->dma->mutex);
-	if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
+	if ((mfd) && (mfd->panel_power_on)) {
 		down(&mfd->sem);
+		spin_lock_irqsave(&mdp_spin_lock, flag);
+		if (mfd->dma->busy == TRUE)
+			need_wait++;
+		spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+		if (need_wait)
+			wait_for_completion_killable(&mfd->dma->comp);
+
+		/* schedule DMA to start */
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mfd->ibuf_flushed = TRUE;
 		mdp_dma2_update_lcd(mfd);
 
@@ -493,15 +505,31 @@
 		mdp_enable_irq(MDP_DMA2_TERM);
 		mfd->dma->busy = TRUE;
 		INIT_COMPLETION(mfd->dma->comp);
-
+		INIT_COMPLETION(vsync_cntrl.vsync_comp);
+		if (!vsync_cntrl.vsync_irq_enabled &&
+				vsync_cntrl.disabled_clocks) {
+			MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
+			outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
+			mdp_intr_mask |= MDP_PRIM_RDPTR;
+			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			mdp_enable_irq(MDP_VSYNC_TERM);
+			vsync_cntrl.vsync_dma_enabled = 1;
+		}
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
 		/* schedule DMA to start */
 		mdp_dma_schedule(mfd, MDP_DMA2_TERM);
 		up(&mfd->sem);
 
-		/* wait until DMA finishes the current job */
-		wait_for_completion_killable(&mfd->dma->comp);
-		mdp_disable_irq(MDP_DMA2_TERM);
+		/* wait until Vsync finishes the current job */
+		if (first_vsync) {
+			if (!wait_for_completion_killable_timeout
+					(&vsync_cntrl.vsync_comp, HZ/10))
+				pr_err("Timedout DMA %s %d", __func__,
+								__LINE__);
+		} else {
+			first_vsync = 1;
+		}
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	/* signal if pan function is waiting for the update completion */
 		if (mfd->pan_waiting) {
@@ -515,28 +543,37 @@
 void mdp_dma_vsync_ctrl(int enable)
 {
 	unsigned long flag;
+	int disabled_clocks;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	if (!enable)
 		INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
 	vsync_cntrl.vsync_irq_enabled = enable;
+	disabled_clocks = vsync_cntrl.disabled_clocks;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-	if (enable) {
+	if (enable && disabled_clocks)
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	if (enable && vsync_cntrl.disabled_clocks &&
+			!vsync_cntrl.vsync_dma_enabled) {
 		MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
-		spin_lock_irqsave(&mdp_spin_lock, flag);
 		outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
 		mdp_intr_mask |= MDP_PRIM_RDPTR;
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 		mdp_enable_irq(MDP_VSYNC_TERM);
-		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	} else {
-		wait_for_completion(&vsync_cntrl.vsync_wait);
-		mdp_disable_irq(MDP_VSYNC_TERM);
+		vsync_cntrl.disabled_clocks = 0;
+	} else if (enable && vsync_cntrl.disabled_clocks) {
+		vsync_cntrl.disabled_clocks = 0;
 	}
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+	if (vsync_cntrl.vsync_irq_enabled &&
+		atomic_read(&vsync_cntrl.suspend) == 0)
+		atomic_set(&vsync_cntrl.vsync_resume, 1);
 }
 
 void mdp_lcd_update_workqueue_handler(struct work_struct *work)
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index a1f2b65..e2fb8ba 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -34,6 +34,33 @@
 static int first_pixel_start_x;
 static int first_pixel_start_y;
 
+static ssize_t vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
+	if (atomic_read(&vsync_cntrl.suspend) > 0 ||
+		atomic_read(&vsync_cntrl.vsync_resume) == 0)
+		return 0;
+
+	wait_for_completion(&vsync_cntrl.vsync_wait);
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+			ktime_to_ns(vsync_cntrl.vsync_time));
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
+
 int mdp_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -88,6 +115,7 @@
 	var = &fbi->var;
 
 	vsync_cntrl.dev = mfd->fbi->dev;
+	atomic_set(&vsync_cntrl.suspend, 0);
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
@@ -226,6 +254,20 @@
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
+	if (!vsync_cntrl.sysfs_created) {
+		ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
+			&vsync_fs_attr_group);
+		if (ret) {
+			pr_err("%s: sysfs creation failed, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
+		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+		vsync_cntrl.sysfs_created = 1;
+	}
+
 	return ret;
 }
 
@@ -241,6 +283,10 @@
 	mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	ret = panel_next_off(pdev);
+
+	atomic_set(&vsync_cntrl.suspend, 1);
+	atomic_set(&vsync_cntrl.vsync_resume, 0);
+	complete_all(&vsync_cntrl.vsync_wait);
 	/* delay to make sure the last frame finishes */
 	msleep(20);
 
@@ -250,16 +296,21 @@
 void mdp_dma_video_vsync_ctrl(int enable)
 {
 	unsigned long flag;
+	int disabled_clocks;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	if (!enable)
 		INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
 	vsync_cntrl.vsync_irq_enabled = enable;
+	if (!enable)
+		vsync_cntrl.disabled_clocks = 0;
+	disabled_clocks = vsync_cntrl.disabled_clocks;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-	if (enable) {
+	if (enable && disabled_clocks) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
@@ -267,10 +318,10 @@
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 		mdp_enable_irq(MDP_VSYNC_TERM);
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	} else {
-		wait_for_completion(&vsync_cntrl.vsync_wait);
-		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
+	if (vsync_cntrl.vsync_irq_enabled &&
+		atomic_read(&vsync_cntrl.suspend) == 0)
+		atomic_set(&vsync_cntrl.vsync_resume, 1);
 }
 
 void mdp_dsi_video_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index 10d60ab..fbfe35f 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -51,6 +51,33 @@
 int first_pixel_start_x;
 int first_pixel_start_y;
 
+static ssize_t vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	if (atomic_read(&vsync_cntrl.suspend) > 0 ||
+		atomic_read(&vsync_cntrl.vsync_resume) == 0)
+		return 0;
+
+	INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
+	wait_for_completion(&vsync_cntrl.vsync_wait);
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+			ktime_to_ns(vsync_cntrl.vsync_time));
+	buf[strlen(buf) + 1] = '\0';
+	return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
+
 int mdp_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -106,6 +133,7 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 	vsync_cntrl.dev = mfd->fbi->dev;
+	atomic_set(&vsync_cntrl.suspend, 0);
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -292,6 +320,20 @@
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
+	if (!vsync_cntrl.sysfs_created) {
+		ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
+			&vsync_fs_attr_group);
+		if (ret) {
+			pr_err("%s: sysfs creation failed, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
+		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+		vsync_cntrl.sysfs_created = 1;
+	}
+
 	return ret;
 }
 
@@ -321,6 +363,9 @@
 
 	ret = panel_next_off(pdev);
 	up(&mfd->dma->mutex);
+	atomic_set(&vsync_cntrl.suspend, 1);
+	atomic_set(&vsync_cntrl.vsync_resume, 0);
+	complete_all(&vsync_cntrl.vsync_wait);
 
 	/* delay to make sure the last frame finishes */
 	msleep(16);
@@ -331,16 +376,21 @@
 void mdp_dma_lcdc_vsync_ctrl(int enable)
 {
 	unsigned long flag;
+	int disabled_clocks;
 	if (vsync_cntrl.vsync_irq_enabled == enable)
 		return;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	if (!enable)
 		INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
 	vsync_cntrl.vsync_irq_enabled = enable;
+	if (!enable)
+		vsync_cntrl.disabled_clocks = 0;
+	disabled_clocks = vsync_cntrl.disabled_clocks;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-	if (enable) {
+	if (enable && disabled_clocks) {
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
@@ -348,10 +398,11 @@
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 		mdp_enable_irq(MDP_VSYNC_TERM);
 		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	} else {
-		wait_for_completion(&vsync_cntrl.vsync_wait);
-		mdp_disable_irq(MDP_VSYNC_TERM);
 	}
+
+	if (vsync_cntrl.vsync_irq_enabled &&
+		atomic_read(&vsync_cntrl.suspend) == 0)
+		atomic_set(&vsync_cntrl.vsync_resume, 1);
 }
 
 void mdp_lcdc_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 758f074..3c60c2b 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -24,8 +24,6 @@
 #define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_res->mdp_base + addr)
 #define MDSS_REG_READ(addr) readl_relaxed(mdss_res->mdp_base + addr)
 
-extern spinlock_t dsi_clk_lock;
-
 enum mdss_mdp_clk_type {
 	MDSS_CLK_AHB,
 	MDSS_CLK_AXI,
@@ -54,6 +52,7 @@
 	u32 irq_buzy;
 
 	u32 mdp_irq_mask;
+	u32 mdp_hist_irq_mask;
 
 	u32 suspend;
 	u32 timeout;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e409a0b..8f4f4d5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -199,11 +199,7 @@
 {
 	int ret = 0;
 
-	spin_lock_bh(&dsi_clk_lock);
 	mdss_dsi_clk_disable(pdata);
-
-	spin_unlock_bh(&dsi_clk_lock);
-
 	mdss_dsi_unprepare_clocks();
 
 	/* disable DSI controller */
@@ -250,11 +246,7 @@
 	mdss_dsi_phy_init(pdata);
 
 	mdss_dsi_prepare_clocks();
-
-	spin_lock_bh(&dsi_clk_lock);
-
 	mdss_dsi_clk_enable(pdata);
-	spin_unlock_bh(&dsi_clk_lock);
 
 	clk_rate = pdata->panel_info.clk_rate;
 	clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -311,6 +303,7 @@
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
 	}
 
+	mdss_dsi_sw_reset(pdata);
 	mdss_dsi_host_init(mipi, pdata);
 
 	if (mipi->force_clk_lane_hs) {
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 5d0d578..125644e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -32,8 +32,6 @@
 static spinlock_t dsi_mdp_lock;
 static int dsi_mdp_busy;
 
-spinlock_t dsi_clk_lock;
-
 struct mdss_hw mdss_dsi_hw = {
 	.hw_ndx = MDSS_HW_DSI0,
 	.ptr = NULL,
@@ -45,7 +43,6 @@
 	init_completion(&dsi_dma_comp);
 	spin_lock_init(&dsi_irq_lock);
 	spin_lock_init(&dsi_mdp_lock);
-	spin_lock_init(&dsi_clk_lock);
 }
 
 void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -816,6 +813,7 @@
 void mdss_dsi_sw_reset(struct mdss_panel_data *pdata)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 dsi_ctrl;
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
@@ -824,6 +822,16 @@
 		return;
 	}
 
+	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
+	dsi_ctrl &= ~0x01;
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
+	wmb();
+
+	/* turn esc, byte, dsi, pclk, sclk, hclk on */
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x11c,
+					0x23f); /* DSI_CLK_CTRL */
+	wmb();
+
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0x01);
 	wmb();
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0x00);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index b247e4d..fd52e1c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -106,8 +106,6 @@
 	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
 		 mipi->mode);
 
-	mdss_dsi_sw_reset(pdata);
-
 	if (mipi->mode == DSI_VIDEO_MODE) {
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
 			num_of_on_cmds);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 739cbd2..9f29887 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -42,6 +42,9 @@
 #include <linux/vmalloc.h>
 
 #include <mach/board.h>
+#include <mach/memory.h>
+#include <mach/msm_memtypes.h>
+#include <mach/iommu_domains.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
@@ -596,37 +599,17 @@
 	size *= mfd->fb_page;
 
 	if (mfd->index == 0) {
-		struct ion_client *iclient = mdss_get_ionclient();
-
-		if (iclient) {
-			mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
-					 ION_HEAP(ION_CP_MM_HEAP_ID) |
-					 ION_HEAP(ION_SF_HEAP_ID), 0);
-			if (IS_ERR_OR_NULL(mfd->ihdl)) {
-				pr_err("unable to alloc fbmem from ion (%p)\n",
-					mfd->ihdl);
-				return -ENOMEM;
-			}
-
-			virt = ion_map_kernel(iclient, mfd->ihdl);
-			ion_phys(iclient, mfd->ihdl, &phys, &size);
-
-			if (is_mdss_iommu_attached()) {
-				ion_map_iommu(iclient, mfd->ihdl,
-					      mdss_get_iommu_domain(),
-					      0, SZ_4K, 0, &mfd->iova,
-					      (unsigned long *) &size,
-					      0, 0);
-			}
-		} else {
-			virt = dma_alloc_coherent(NULL, size,
-					(dma_addr_t *) &phys, GFP_KERNEL);
-			if (!virt) {
-				pr_err("unable to alloc fbmem size=%u\n", size);
-				return -ENOMEM;
-			}
+		virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+		if (!virt) {
+			pr_err("unable to alloc fbmem size=%u\n", size);
+			return -ENOMEM;
 		}
-
+		phys = memory_pool_node_paddr(virt);
+		if (is_mdss_iommu_attached()) {
+			msm_iommu_map_contig_buffer(phys,
+				mdss_get_iommu_domain(), 0, size, SZ_4K, 0,
+				&(mfd->iova));
+		}
 		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
 			size, virt, phys, mfd->index);
 	} else {
@@ -946,7 +929,6 @@
 			     struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	u32 len;
 
 	if (var->rotate != FB_ROTATE_UR)
 		return -EINVAL;
@@ -1025,9 +1007,12 @@
 	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
 		return -EINVAL;
 
-	len = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
-	if (len > info->fix.smem_len)
-		return -EINVAL;
+	if (info->fix.smem_start) {
+		u32 len = var->xres_virtual * var->yres_virtual *
+			(var->bits_per_pixel / 8);
+		if (len > info->fix.smem_len)
+			return -EINVAL;
+	}
 
 	if ((var->xres == 0) || (var->yres == 0))
 		return -EINVAL;
@@ -1151,6 +1136,46 @@
 		ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
 				&copyback);
 		break;
+
+	case mdp_op_pcc_cfg:
+		ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
+			   &copyback);
+		break;
+
+	case mdp_op_lut_cfg:
+		switch (mdp_pp.data.lut_cfg_data.lut_type) {
+		case mdp_lut_igc:
+			ret = mdss_mdp_igc_lut_config(
+					(struct mdp_igc_lut_data *)
+					&mdp_pp.data.lut_cfg_data.data,
+					&copyback);
+			break;
+
+		case mdp_lut_pgc:
+			ret = mdss_mdp_argc_config(
+				&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
+				&copyback);
+			break;
+
+		case mdp_lut_hist:
+			ret = mdss_mdp_hist_lut_config(
+				(struct mdp_hist_lut_data *)
+				&mdp_pp.data.lut_cfg_data.data, &copyback);
+			break;
+
+		default:
+			ret = -ENOTSUPP;
+			break;
+		}
+		break;
+	case mdp_op_dither_cfg:
+		ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
+				&copyback);
+		break;
+	case mdp_op_gamut_cfg:
+		ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
+				&copyback);
+		break;
 	default:
 		pr_err("Unsupported request to MDP_PP IOCTL.\n");
 		ret = -EINVAL;
@@ -1166,6 +1191,9 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	void __user *argp = (void __user *)arg;
+	struct mdp_histogram_data hist;
+	struct mdp_histogram_start_req hist_req;
+	u32 block, hist_data_addr = 0;
 	struct mdp_page_protection fb_page_protection;
 	int ret = -ENOSYS;
 
@@ -1178,6 +1206,43 @@
 		ret = mdss_fb_set_lut(info, argp);
 		break;
 
+	case MSMFB_HISTOGRAM:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist, argp, sizeof(hist));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_hist_collect(info, &hist, &hist_data_addr);
+		if ((ret == 0) && hist_data_addr) {
+			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
+				sizeof(u32) * hist.bin_cnt);
+			if (ret == 0)
+				ret = copy_to_user(argp, &hist,
+						   sizeof(hist));
+		}
+		break;
+
+	case MSMFB_HISTOGRAM_START:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_start(&hist_req);
+		break;
+
+	case MSMFB_HISTOGRAM_STOP:
+		ret = copy_from_user(&block, argp, sizeof(int));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_stop(block);
+		break;
+
 	case MSMFB_GET_PAGE_PROTECTION:
 		fb_page_protection.page_protection =
 			mfd->mdp_fb_page_protection;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index f720a2f..8db38d6 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -358,34 +358,25 @@
 		DEV_DBG("EDID: reading block(%d) with block-size=%d\n",
 			block, block_size);
 		for (i = 0; i < 0x80; i += block_size) {
-			/*Read EDID twice with 32bit alighnment too */
-			if (block < 2) {
-				memset(&ddc_data, 0, sizeof(ddc_data));
-				ddc_data.dev_addr = 0xA0;
-				ddc_data.offset   = block*0x80 + i;
-				ddc_data.data_buf = edid_buf+i;
-				ddc_data.data_len = block_size;
-				ddc_data.retry    = 1;
-				ddc_data.what     = "EDID";
-				ddc_data.no_align = false;
+			memset(&ddc_data, 0, sizeof(ddc_data));
+			ddc_data.dev_addr    = 0xA0;
+			ddc_data.offset      = block*0x80 + i;
+			ddc_data.data_buf    = edid_buf+i;
+			ddc_data.data_len    = block_size;
+			ddc_data.request_len = block_size;
+			ddc_data.retry       = 1;
+			ddc_data.what        = "EDID";
+			ddc_data.no_align    = false;
 
+			/*Read EDID twice with 32bit alighnment too */
+			if (block < 2)
 				status = hdmi_ddc_read(
 					edid_ctrl->init_data.ddc_ctrl,
 					&ddc_data);
-			} else {
-				memset(&ddc_data, 0, sizeof(ddc_data));
-				ddc_data.dev_addr    = 0xA0;
-				ddc_data.offset      = block*0x80 + i;
-				ddc_data.data_buf    = edid_buf+i;
-				ddc_data.data_len    = block_size;
-				ddc_data.request_len = block_size;
-				ddc_data.retry       = 1;
-				ddc_data.what        = "EDID";
-
+			else
 				status = hdmi_ddc_read_seg(
 					edid_ctrl->init_data.ddc_ctrl,
 					&ddc_data);
-			}
 			if (status)
 				break;
 		}
@@ -413,7 +404,7 @@
 	}
 
 	print_len = 0x80;
-	for (ndx = 0; ndx < print_len; ndx += 16)
+	for (ndx = 0; ndx < print_len; ndx += 4)
 		DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
 			ndx, ndx+3,
 			b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
@@ -1392,7 +1383,7 @@
 {
 	struct hdmi_edid_ctrl *edid_ctrl = NULL;
 
-	if (!init_data || !init_data->base ||
+	if (!init_data || !init_data->io ||
 		!init_data->mutex || !init_data->sysfs_kobj ||
 		!init_data->ddc_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h
index d10ae49..5c51e7e 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h
@@ -16,7 +16,7 @@
 #include "mdss_hdmi_util.h"
 
 struct hdmi_edid_init_data {
-	void __iomem *base;
+	struct dss_io_data *io;
 	struct mutex *mutex;
 	struct kobject *sysfs_kobj;
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 9278029..7f41221 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/bitops.h>
-#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -20,7 +19,7 @@
 #include <linux/of_gpio.h>
 #include <linux/types.h>
 
-/* #define DEBUG */
+#define REG_DUMP 0
 
 #include "mdss_fb.h"
 #include "mdss_hdmi_tx.h"
@@ -91,19 +90,19 @@
 	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02, 0x02}  /*12*/
 };
 
-static const char *hdmi_tx_clk_name(u32 clk)
+const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
 {
-	switch (clk) {
-	case HDMI_TX_AHB_CLK:	return "hdmi_ahb_clk";
-	case HDMI_TX_APP_CLK:	return "hdmi_app_clk";
-	case HDMI_TX_EXTP_CLK:	return "hdmi_extp_clk";
-	default:		return "???";
+	switch (module) {
+	case HDMI_TX_HPD_PM:	return "HDMI_TX_HPD_PM";
+	case HDMI_TX_CORE_PM:	return "HDMI_TX_CORE_PM";
+	case HDMI_TX_CEC_PM:	return "HDMI_TX_CEC_PM";
+	default: return "???";
 	}
-} /* hdmi_tx_clk_name */
+} /* hdmi_tx_pm_name */
 
-static const char *hdmi_tx_io_name(u32 io)
+static const char *hdmi_tx_io_name(u32 type)
 {
-	switch (io) {
+	switch (type) {
 	case HDMI_TX_CORE_IO:	return "core_physical";
 	case HDMI_TX_PHY_IO:	return "phy_physical";
 	case HDMI_TX_QFPROM_IO:	return "qfprom_physical";
@@ -190,75 +189,6 @@
 	return ret;
 } /* hdmi_tx_sysfs_rda_connected */
 
-static ssize_t hdmi_tx_sysfs_rda_fake_hpd(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	ssize_t ret;
-	struct hdmi_tx_ctrl *hdmi_ctrl =
-		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
-
-	if (!hdmi_ctrl) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	mutex_lock(&hdmi_ctrl->mutex);
-	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
-	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
-	mutex_unlock(&hdmi_ctrl->mutex);
-
-	return ret;
-} /* hdmi_tx_sysfs_rda_fake_hpd */
-
-static ssize_t hdmi_tx_sysfs_wta_fake_hpd(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t count)
-{
-	int fake_hpd, rc = 0;
-	ssize_t ret = strnlen(buf, PAGE_SIZE);
-	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-
-	DEV_DBG("%s:\n", __func__);
-	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
-
-	if (!hdmi_ctrl) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	rc = kstrtoint(buf, 10, &fake_hpd);
-	if (rc) {
-		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
-		return rc;
-	}
-
-	mutex_lock(&hdmi_ctrl->mutex);
-	DEV_INFO("%s: fake_hpd=%d\n", __func__, fake_hpd);
-	if (fake_hpd) {
-		hdmi_ctrl->hpd_state = true;
-
-		/* todo: Remove this once HPD line is available in HW */
-		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
-		if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE))
-			DEV_ERR("%s: failed sending online event\n", __func__);
-		switch_set_state(&hdmi_ctrl->sdev, 1);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
-	} else {
-		hdmi_ctrl->hpd_state = false;
-
-		/* todo: Remove this once HPD line is available in HW */
-		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
-		if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE))
-			DEV_ERR("%s: failed sending online event\n", __func__);
-		switch_set_state(&hdmi_ctrl->sdev, 0);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
-	}
-	mutex_unlock(&hdmi_ctrl->mutex);
-
-	return ret;
-} /* hdmi_tx_sysfs_wta_fake_hpd */
-
 static ssize_t hdmi_tx_sysfs_rda_hpd(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -298,16 +228,13 @@
 		return rc;
 	}
 
-	/* todo: Remove this once HPD line is available in HW */
-	if (0) {
-		if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
-			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
-		} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
-			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
-		} else {
-			rc = -EPERM;
-			ret = rc;
-		}
+	if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
+		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+	} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
+		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+	} else {
+		rc = -EPERM;
+		ret = rc;
 	}
 
 	if (!rc) {
@@ -325,13 +252,10 @@
 static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
 static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
 	hdmi_tx_sysfs_wta_hpd);
-static DEVICE_ATTR(fake_hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_fake_hpd,
-	hdmi_tx_sysfs_wta_fake_hpd);
 
 static struct attribute *hdmi_tx_fs_attrs[] = {
 	&dev_attr_connected.attr,
 	&dev_attr_hpd.attr,
-	&dev_attr_fake_hpd.attr,
 	NULL,
 };
 static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -385,7 +309,7 @@
 		return -EINVAL;
 	}
 
-	edid_init_data.base = hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base;
+	edid_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 	edid_init_data.mutex = &hdmi_ctrl->mutex;
 	edid_init_data.sysfs_kobj = hdmi_ctrl->kobj;
 	edid_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
@@ -405,14 +329,14 @@
 
 static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
-		HDMI_CTRL) & BIT(0);
+	struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0);
 } /* hdmi_tx_is_controller_on */
 
 static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	return !(HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
-		HDMI_CTRL) & BIT(1));
+	struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	return !(DSS_REG_R_ND(io, HDMI_CTRL) & BIT(1));
 } /* hdmi_tx_is_dvi_mode */
 
 static int hdmi_tx_init_panel_info(uint32_t resolution,
@@ -473,44 +397,6 @@
 	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
 } /* hdmi_tx_setup_video_mode_lut */
 
-static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
-	u32 clk_idx)
-{
-	if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return NULL;
-	}
-
-	return pdata->clk[clk_idx];
-} /* hdmi_tx_get_clk */
-
-static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
-	u32 clk_idx, unsigned long clk_rate)
-{
-	int rc = 0;
-	struct clk *clk = NULL;
-
-	if (!pdata) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	clk = hdmi_tx_get_clk(pdata, clk_idx);
-	if (clk) {
-		rc = clk_set_rate(clk, clk_rate);
-		if (IS_ERR_VALUE(rc))
-			DEV_ERR("%s: failed rc=%d\n", __func__, rc);
-		else
-			DEV_DBG("%s: name='%s' rate=%lu\n", __func__,
-				hdmi_tx_clk_name(clk_idx), clk_rate);
-	} else {
-		DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
-		rc = -EINVAL;
-	}
-
-	return rc;
-} /* hdmi_tx_clk_set_rate */
-
 static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	int status;
@@ -551,9 +437,14 @@
 	}
 
 	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
 	DEV_DBG("%s: Got HPD interrupt\n", __func__);
 
-	hpd_state = (HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+	hpd_state = (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
 	mutex_lock(&hdmi_ctrl->mutex);
 	if ((hdmi_ctrl->hpd_prev_state != hdmi_ctrl->hpd_state) ||
 		(hdmi_ctrl->hpd_state != hpd_state)) {
@@ -605,22 +496,62 @@
 	}
 
 	/* Set IRQ for HPD */
-	HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
+	DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
 } /* hdmi_tx_hpd_state_work */
 
-static int hdmi_tx_check_capability(void __iomem *base)
+static void hdmi_tx_hpd_int_work(struct work_struct *work)
+{
+	u32 hpd_int_status;
+	u32 hpd_int_ctrl;
+	u32 cable_detected;
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct dss_io_data *io = NULL;
+
+	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
+	if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+		DEV_DBG("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	/* Process HPD Interrupt */
+	hpd_int_status = DSS_REG_R(io, HDMI_HPD_INT_STATUS);
+	hpd_int_ctrl = DSS_REG_R(io, HDMI_HPD_INT_CTRL);
+
+	DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2));
+
+	cable_detected = hpd_int_status & BIT(1);
+	mutex_lock(&hdmi_ctrl->mutex);
+	hdmi_ctrl->hpd_cable_chg_detected = true;
+	hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
+	hdmi_ctrl->hpd_stable = 0;
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+	DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
+		hpd_int_status);
+} /* hdmi_tx_hpd_int_work */
+
+static int hdmi_tx_check_capability(struct dss_io_data *io)
 {
 	u32 hdmi_disabled, hdcp_disabled;
 
-	if (!base) {
+	if (!io) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
 
-	/* QFPROM_RAW_FEAT_CONFIG_ROW0_LSB */
-	hdcp_disabled = HDMI_REG_R_ND(base, 0x000000F8) & BIT(31);
-	/* QFPROM_RAW_FEAT_CONFIG_ROW0_MSB */
-	hdmi_disabled = HDMI_REG_R_ND(base, 0x000000FC) & BIT(0);
+	hdcp_disabled = DSS_REG_R_ND(io,
+		QFPROM_RAW_FEAT_CONFIG_ROW0_LSB) & BIT(31);
+
+	hdmi_disabled = DSS_REG_R_ND(io,
+		QFPROM_RAW_FEAT_CONFIG_ROW0_MSB) & BIT(0);
 
 	DEV_DBG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__,
 		hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON");
@@ -710,25 +641,9 @@
 		goto end;
 	}
 
-	/*
-	 * extpclk is driven by hdmi phy pll. This phy pll programming requires
-	 * hdmi_ahb_clk. So enable it and then disable.
-	 */
-	rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
-	if (rc) {
-		DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
-		goto end;
-	}
-	rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
-		timing->pixel_freq * 1000);
-	if (rc) {
-		DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
-		clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
-		goto end;
-	}
-	clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+	/* todo: find a better way */
+	hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate =
+		timing->pixel_freq * 1000;
 
 	hdmi_ctrl->video_resolution = format;
 	hdmi_edid_set_video_resolution(
@@ -772,35 +687,35 @@
 		timing->back_porch_h + timing->pulse_width_h - 1;
 	total_v = timing->active_v + timing->front_porch_v +
 		timing->back_porch_v + timing->pulse_width_v - 1;
-	HDMI_REG_W(io->base, HDMI_TOTAL,
+	DSS_REG_W(io, HDMI_TOTAL,
 		((total_v << 16) & 0x0FFF0000) |
 		((total_h << 0) & 0x00000FFF));
 
 	start_h = timing->back_porch_h + timing->pulse_width_h;
 	end_h   = (total_h + 1) - timing->front_porch_h;
-	HDMI_REG_W(io->base, HDMI_ACTIVE_H,
+	DSS_REG_W(io, HDMI_ACTIVE_H,
 		((end_h << 16) & 0x0FFF0000) |
 		((start_h << 0) & 0x00000FFF));
 
 	start_v = timing->back_porch_v + timing->pulse_width_v - 1;
 	end_v   = total_v - timing->front_porch_v;
-	HDMI_REG_W(io->base, HDMI_ACTIVE_V,
+	DSS_REG_W(io, HDMI_ACTIVE_V,
 		((end_v << 16) & 0x0FFF0000) |
 		((start_v << 0) & 0x00000FFF));
 
 	if (timing->interlaced) {
-		HDMI_REG_W(io->base, HDMI_V_TOTAL_F2,
+		DSS_REG_W(io, HDMI_V_TOTAL_F2,
 			((total_v + 1) << 0) & 0x00000FFF);
 
-		HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2,
+		DSS_REG_W(io, HDMI_ACTIVE_V_F2,
 			(((start_v + 1) << 0) & 0x00000FFF) |
 			(((end_v + 1) << 16) & 0x0FFF0000));
 	} else {
-		HDMI_REG_W(io->base, HDMI_V_TOTAL_F2, 0);
-		HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2, 0);
+		DSS_REG_W(io, HDMI_V_TOTAL_F2, 0);
+		DSS_REG_W(io, HDMI_ACTIVE_V_F2, 0);
 	}
 
-	HDMI_REG_W(io->base, HDMI_FRAME_CTRL,
+	DSS_REG_W(io, HDMI_FRAME_CTRL,
 		((timing->interlaced << 31) & 0x80000000) |
 		((timing->active_low_h << 29) & 0x20000000) |
 		((timing->active_low_v << 28) & 0x10000000));
@@ -929,28 +844,28 @@
 	regVal = regVal << 8 | avi_iframe[4];
 	regVal = regVal << 8 | avi_iframe[3];
 	regVal = regVal << 8 | checksum;
-	HDMI_REG_W(io->base, HDMI_AVI_INFO0, regVal);
+	DSS_REG_W(io, HDMI_AVI_INFO0, regVal);
 
 	regVal = avi_iframe[9];
 	regVal = regVal << 8 | avi_iframe[8];
 	regVal = regVal << 8 | avi_iframe[7];
 	regVal = regVal << 8 | avi_iframe[6];
-	HDMI_REG_W(io->base, HDMI_AVI_INFO1, regVal);
+	DSS_REG_W(io, HDMI_AVI_INFO1, regVal);
 
 	regVal = avi_iframe[13];
 	regVal = regVal << 8 | avi_iframe[12];
 	regVal = regVal << 8 | avi_iframe[11];
 	regVal = regVal << 8 | avi_iframe[10];
-	HDMI_REG_W(io->base, HDMI_AVI_INFO2, regVal);
+	DSS_REG_W(io, HDMI_AVI_INFO2, regVal);
 
 	regVal = avi_iframe[1];
 	regVal = regVal << 16 | avi_iframe[15];
 	regVal = regVal << 8 | avi_iframe[14];
-	HDMI_REG_W(io->base, HDMI_AVI_INFO3, regVal);
+	DSS_REG_W(io, HDMI_AVI_INFO3, regVal);
 
 	/* 0x3 for AVI InfFrame enable (every frame) */
-	HDMI_REG_W(io->base, HDMI_INFOFRAME_CTRL0,
-		HDMI_REG_R(io->base, HDMI_INFOFRAME_CTRL0) |
+	DSS_REG_W(io, HDMI_INFOFRAME_CTRL0,
+		DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) |
 		0x00000003L);
 } /* hdmi_tx_set_avi_infoframe */
 
@@ -986,14 +901,14 @@
 	 * 0x19 Length of Source Product Description InfoFrame
 	 */
 	packet_header  = 0x83 | (0x01 << 8) | (0x19 << 16);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_HDR, packet_header);
+	DSS_REG_W(io, HDMI_GENERIC1_HDR, packet_header);
 	check_sum += IFRAME_CHECKSUM_32(packet_header);
 
 	packet_payload = (vendor_name[3] & 0x7f)
 		| ((vendor_name[4] & 0x7f) << 8)
 		| ((vendor_name[5] & 0x7f) << 16)
 		| ((vendor_name[6] & 0x7f) << 24);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_1, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_1, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
 	/* Product Description (7-bit ASCII code) */
@@ -1001,28 +916,28 @@
 		| ((product_description[0] & 0x7f) << 8)
 		| ((product_description[1] & 0x7f) << 16)
 		| ((product_description[2] & 0x7f) << 24);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_2, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_2, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
 	packet_payload = (product_description[3] & 0x7f)
 		| ((product_description[4] & 0x7f) << 8)
 		| ((product_description[5] & 0x7f) << 16)
 		| ((product_description[6] & 0x7f) << 24);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_3, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_3, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
 	packet_payload = (product_description[7] & 0x7f)
 		| ((product_description[8] & 0x7f) << 8)
 		| ((product_description[9] & 0x7f) << 16)
 		| ((product_description[10] & 0x7f) << 24);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_4, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_4, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
 	packet_payload = (product_description[11] & 0x7f)
 		| ((product_description[12] & 0x7f) << 8)
 		| ((product_description[13] & 0x7f) << 16)
 		| ((product_description[14] & 0x7f) << 24);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_5, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_5, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
 	/*
@@ -1039,7 +954,7 @@
 	 * 09h PC general
 	 */
 	packet_payload = (product_description[15] & 0x7f) | 0x00 << 8;
-	HDMI_REG_W(io->base, HDMI_GENERIC1_6, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_6, packet_payload);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 
 	/* Vendor Name (7bit ASCII code) */
@@ -1048,7 +963,7 @@
 		| ((vendor_name[2] & 0x7f) << 24);
 	check_sum += IFRAME_CHECKSUM_32(packet_payload);
 	packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
-	HDMI_REG_W(io->base, HDMI_GENERIC1_0, packet_payload);
+	DSS_REG_W(io, HDMI_GENERIC1_0, packet_payload);
 
 	/*
 	 * GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
@@ -1056,9 +971,9 @@
 	 * Enable this packet to transmit every frame
 	 * Enable HDMI TX engine to transmit Generic packet 1
 	 */
-	packet_control = HDMI_REG_R_ND(io->base, HDMI_GEN_PKT_CTRL);
+	packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL);
 	packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4));
-	HDMI_REG_W(io->base, HDMI_GEN_PKT_CTRL, packet_control);
+	DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control);
 } /* hdmi_tx_set_spd_infoframe */
 
 /* todo: revisit when new HPD debouncing logic is avialble */
@@ -1075,11 +990,17 @@
 static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
 {
 	u32 reg_val = 0;
+	struct dss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return;
 	}
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
 
 	if (power_on) {
 		/* ENABLE */
@@ -1101,77 +1022,12 @@
 		reg_val = BIT(1);
 	}
 
-	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, HDMI_CTRL,
-		reg_val);
+	DSS_REG_W(io, HDMI_CTRL, reg_val);
 
 	DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
 		power_on ? "Enable" : "Disable", reg_val);
 } /* hdmi_tx_set_mode */
 
-static int hdmi_tx_clk_update(struct hdmi_tx_platform_data *pdata, u32 clk_idx,
-	u32 enable)
-{
-	int rc = 0;
-	struct clk *clk = hdmi_tx_get_clk(pdata, clk_idx);
-
-	if (clk) {
-		DEV_DBG("%s: clk=%d en=%d\n", __func__, clk_idx, enable);
-		if (enable) {
-			rc = clk_prepare_enable(clk);
-			if (rc)
-				DEV_ERR("%s: clk=%d enable failed\n",
-				__func__, clk_idx);
-		} else {
-			clk_disable_unprepare(clk);
-		}
-	} else {
-		DEV_ERR("%s: FAILED: invalid input for clk='%s'\n", __func__,
-			hdmi_tx_clk_name(clk_idx));
-		rc = -EINVAL;
-	}
-
-	return rc;
-} /* hdmi_tx_clk_update */
-
-/* Note: Before accessing extpclk, always make sure that hdmi_ahb_clk is on */
-static int hdmi_tx_clk_ctrl_update(struct hdmi_tx_platform_data *pdata, int on)
-{
-	int  rc = 0;
-	DEV_DBG("%s: HDMI Clk: %s\n", __func__, on ? "Enable" : "Disable");
-
-	rc = hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, on);
-	if (on && rc) {
-		DEV_ERR("%s: '%s' on failed\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_APP_CLK));
-		goto fail_hdmi_app_clk;
-	}
-	if (on) {
-		rc = hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
-		if (rc) {
-			DEV_ERR("%s: '%s' on failed\n", __func__,
-				hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
-			goto fail_hdmi_ahb_clk;
-		}
-		rc = hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
-		if (rc) {
-			DEV_ERR("%s: '%s' on failed\n", __func__,
-				hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
-			goto fail_hdmi_extp_clk;
-		}
-	} else {
-		hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
-		hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
-	}
-	return rc;
-
-fail_hdmi_extp_clk:
-	hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, 0);
-fail_hdmi_ahb_clk:
-	hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, 0);
-fail_hdmi_app_clk:
-	return rc;
-} /* hdmi_tx_clk_ctrl_update */
-
 static int hdmi_tx_config_power(struct hdmi_tx_ctrl *hdmi_ctrl,
 	enum hdmi_tx_power_module_type module, int config)
 {
@@ -1191,17 +1047,33 @@
 		goto exit;
 	}
 
-	if (config)
+	if (config) {
 		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 1);
-	else
+		if (rc) {
+			DEV_ERR("%s: Failed to config %s vreg. Err=%d\n",
+				__func__, hdmi_tx_pm_name(module), rc);
+			goto exit;
+		}
+
+		rc = msm_dss_get_clk(&hdmi_ctrl->pdev->dev,
+			power_data->clk_config, power_data->num_clk);
+		if (rc) {
+			DEV_ERR("%s: Failed to get %s clk. Err=%d\n",
+				__func__, hdmi_tx_pm_name(module), rc);
+
+			msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			power_data->vreg_config, power_data->num_vreg, 0);
+		}
+	} else {
+		msm_dss_put_clk(power_data->clk_config, power_data->num_clk);
+
 		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
-
-	if (rc)
-		DEV_ERR("%s: Failed to %s %s vreg. Error=%d\n",
-			__func__, config ? "config" : "deconfig",
-			hdmi_pm_name(module), rc);
+		if (rc)
+			DEV_ERR("%s: Fail to deconfig %s vreg. Err=%d\n",
+				__func__, hdmi_tx_pm_name(module), rc);
+	}
 
 exit:
 	return rc;
@@ -1231,18 +1103,36 @@
 			power_data->num_vreg, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
-				__func__, hdmi_pm_name(module), rc);
+				__func__, hdmi_tx_pm_name(module), rc);
 			goto error;
 		}
 
 		rc = msm_dss_enable_gpio(power_data->gpio_config,
-			power_data->num_gpio, enable);
+			power_data->num_gpio, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
-				__func__, hdmi_pm_name(module), rc);
+				__func__, hdmi_tx_pm_name(module), rc);
 			goto disable_vreg;
 		}
+
+		rc = msm_dss_clk_set_rate(power_data->clk_config,
+			power_data->num_clk);
+		if (rc) {
+			DEV_ERR("%s: failed to set clks rate for %s. err=%d\n",
+				__func__, hdmi_tx_pm_name(module), rc);
+			goto disable_gpio;
+		}
+
+		rc = msm_dss_enable_clk(power_data->clk_config,
+			power_data->num_clk, 1);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable clks for %s. Error=%d\n",
+				__func__, hdmi_tx_pm_name(module), rc);
+			goto disable_gpio;
+		}
 	} else {
+		msm_dss_enable_clk(power_data->clk_config,
+			power_data->num_clk, 0);
 		msm_dss_enable_gpio(power_data->gpio_config,
 			power_data->num_gpio, 0);
 		msm_dss_enable_vreg(power_data->vreg_config,
@@ -1251,6 +1141,8 @@
 
 	return rc;
 
+disable_gpio:
+	msm_dss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0);
 disable_vreg:
 	msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
 error:
@@ -1281,7 +1173,7 @@
 	if (rc) {
 		DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
 			__func__, rc);
-		goto error;
+		goto disable_hpd_power;
 	}
 	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
 	if (rc) {
@@ -1293,7 +1185,8 @@
 	return rc;
 disable_core_power:
 	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
-error:
+disable_hpd_power:
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
 	return rc;
 } /* hdmi_tx_core_on */
 
@@ -1311,36 +1204,34 @@
 
 	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 	if (!io->base) {
-		DEV_ERR("%s: io not inititalized\n", __func__);
+		DEV_ERR("%s: core io not inititalized\n", __func__);
 		return;
 	}
 
-	val = HDMI_REG_R_ND(io->base, HDMI_PHY_CTRL);
+	val = DSS_REG_R_ND(io, HDMI_PHY_CTRL);
 
 	phy_reset_polarity = val >> 3 & 0x1;
 	pll_reset_polarity = val >> 1 & 0x1;
 
 	if (phy_reset_polarity == 0)
-		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET);
 	else
-		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET));
 
 	if (pll_reset_polarity == 0)
-		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
 	else
-		HDMI_REG_W_ND(io->base,
-			HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
 
 	if (phy_reset_polarity == 0)
-		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET));
 	else
-		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET);
 
 	if (pll_reset_polarity == 0)
-		HDMI_REG_W_ND(io->base,
-			HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
 	else
-		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
 } /* hdmi_tx_phy_reset */
 
 static void hdmi_tx_init_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -1354,55 +1245,58 @@
 
 	io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
 	if (!io->base) {
-		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		DEV_ERR("%s: phy io is not initialized\n", __func__);
 		return;
 	}
 
-	HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG0, 0x1B);
-	HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG1, 0xF2);
-	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_CFG0, 0x0);
-	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN0, 0x0);
-	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN1, 0x0);
-	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN2, 0x0);
-	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN3, 0x0);
+	DSS_REG_W_ND(io, HDMI_PHY_ANA_CFG0, 0x1B);
+	DSS_REG_W_ND(io, HDMI_PHY_ANA_CFG1, 0xF2);
+	DSS_REG_W_ND(io, HDMI_PHY_BIST_CFG0, 0x0);
+	DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN0, 0x0);
+	DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN1, 0x0);
+	DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN2, 0x0);
+	DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN3, 0x0);
 
-	HDMI_REG_W_ND(io->base, HDMI_PHY_PD_CTRL1, 0x20);
+	DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL1, 0x20);
 } /* hdmi_tx_init_phy */
 
 static void hdmi_tx_powerdown_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
+	struct dss_io_data *io = NULL;
+
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return;
 	}
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
+	if (!io->base) {
+		DEV_ERR("%s: phy io is not initialized\n", __func__);
+		return;
+	}
 
-	HDMI_REG_W_ND(hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO].base,
-		HDMI_PHY_PD_CTRL0, 0x7F);
+	DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL0, 0x7F);
 } /* hdmi_tx_powerdown_phy */
 
 static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	int rc = 0;
+	struct dss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io is not initialized\n", __func__);
+		return -EINVAL;
+	}
+
 	/* todo: Audio */
 
 	hdmi_tx_set_mode(hdmi_ctrl, false);
-	mutex_lock(&hdmi_ctrl->mutex);
-	rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 1);
-	if (rc) {
-		DEV_ERR("%s: hdmi_tx_clk_enable failed.\n", __func__);
-		mutex_unlock(&hdmi_ctrl->mutex);
-		return rc;
-	}
-	mutex_unlock(&hdmi_ctrl->mutex);
-
 	hdmi_tx_init_phy(hdmi_ctrl);
-	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
-		HDMI_USEC_REFTIMER, 0x0001001B);
+	DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);
 
 	hdmi_tx_set_mode(hdmi_ctrl, true);
 
@@ -1413,8 +1307,7 @@
 	hdmi_tx_set_spd_infoframe(hdmi_ctrl);
 
 	/* Set IRQ for HPD */
-	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
-		HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
+	DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
 
 	/* todo: HDCP/CEC */
 
@@ -1437,12 +1330,6 @@
 	/* todo: Audio */
 	hdmi_tx_powerdown_phy(hdmi_ctrl);
 	hdmi_ctrl->panel_power_on = false;
-
-	mutex_lock(&hdmi_ctrl->mutex);
-	if (hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0))
-		DEV_ERR("%s: hdmi_tx_clk_disable failed.\n", __func__);
-	mutex_unlock(&hdmi_ctrl->mutex);
-
 	hdmi_tx_core_off(hdmi_ctrl);
 
 	return 0;
@@ -1451,6 +1338,7 @@
 static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
 {
 	int rc = 0;
+	struct dss_io_data *io = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
 		hdmi_tx_get_drvdata_from_panel_data(panel_data);
 
@@ -1458,11 +1346,10 @@
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
-
-	rc = hdmi_tx_core_on(hdmi_ctrl);
-	if (rc) {
-		DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
-		return rc;
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io is not initialized\n", __func__);
+		return -EINVAL;
 	}
 
 	DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
@@ -1471,7 +1358,12 @@
 	rc = hdmi_tx_set_video_fmt(hdmi_ctrl);
 	if (rc) {
 		DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
-		hdmi_tx_core_off(hdmi_ctrl);
+		return rc;
+	}
+
+	rc = hdmi_tx_core_on(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
 		return rc;
 	}
 
@@ -1494,8 +1386,7 @@
 		mutex_unlock(&hdmi_ctrl->mutex);
 	}
 
-	hdmi_reg_dump(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
-		hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len, "HDMI-ON: ");
+	dss_reg_dump(io->base, io->len, "HDMI-ON: ", REG_DUMP);
 
 	DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__,
 		hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" ,
@@ -1524,13 +1415,6 @@
 
 	hdmi_tx_set_mode(hdmi_ctrl, false);
 
-	mutex_lock(&hdmi_ctrl->mutex);
-	rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0);
-	if (rc)
-		DEV_INFO("%s: Failed to disable clock. Error=%d\n",
-			__func__, rc);
-	mutex_unlock(&hdmi_ctrl->mutex);
-
 	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
 	if (rc)
 		DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
@@ -1552,7 +1436,7 @@
 
 	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 	if (!io->base) {
-		DEV_ERR("%s: io not inititalized\n", __func__);
+		DEV_ERR("%s: core io not inititalized\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1566,31 +1450,21 @@
 			return rc;
 		}
 
-		mutex_lock(&hdmi_ctrl->mutex);
-		rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, true);
-		if (rc) {
-			DEV_ERR("%s: Failed to enable clocks. rc=%d\n",
-				__func__, rc);
-			mutex_unlock(&hdmi_ctrl->mutex);
-			goto disable_hpd_power;
-		}
-		mutex_unlock(&hdmi_ctrl->mutex);
-
-		hdmi_reg_dump(io->base, io->len, "HDMI-INIT: ");
+		dss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);
 
 		hdmi_tx_set_mode(hdmi_ctrl, false);
 		hdmi_tx_phy_reset(hdmi_ctrl);
 		hdmi_tx_set_mode(hdmi_ctrl, true);
 
-		HDMI_REG_W(io->base, HDMI_USEC_REFTIMER, 0x0001001B);
+		DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);
 
 		/* set timeout to 4.1ms (max) for hardware debounce */
-		reg_val = HDMI_REG_R(io->base, HDMI_HPD_CTRL) | 0x1FFF;
+		reg_val = DSS_REG_R(io, HDMI_HPD_CTRL) | 0x1FFF;
 
 		/* Toggle HPD circuit to trigger HPD sense */
-		HDMI_REG_W(io->base, HDMI_HPD_CTRL,
+		DSS_REG_W(io, HDMI_HPD_CTRL,
 			~(1 << 28) & reg_val);
-		HDMI_REG_W(io->base, HDMI_HPD_CTRL, (1 << 28) | reg_val);
+		DSS_REG_W(io, HDMI_HPD_CTRL, (1 << 28) | reg_val);
 
 		hdmi_ctrl->hpd_initialized = true;
 
@@ -1607,11 +1481,6 @@
 	mutex_unlock(&hdmi_ctrl->mutex);
 	mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
 
-	return 0;
-
-disable_hpd_power:
-	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, false);
-
 	return rc;
 } /* hdmi_tx_hpd_on */
 
@@ -1629,7 +1498,6 @@
 		rc = hdmi_tx_hpd_on(hdmi_ctrl);
 	} else {
 		hdmi_tx_hpd_off(hdmi_ctrl);
-		/* Set HDMI switch node to 0 on HPD feature disable */
 		switch_set_state(&hdmi_ctrl->sdev, 0);
 		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
 			hdmi_ctrl->sdev.state);
@@ -1640,8 +1508,6 @@
 
 static irqreturn_t hdmi_tx_isr(int irq, void *data)
 {
-	u32 hpd_int_status;
-	u32 hpd_int_ctrl;
 	struct dss_io_data *io = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
 
@@ -1652,108 +1518,26 @@
 
 	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 	if (!io->base) {
-		DEV_WARN("%s: io not initialized, ISR ignored\n", __func__);
+		DEV_WARN("%s: core io not initialized, ISR ignored\n",
+			__func__);
 		return IRQ_HANDLED;
 	}
 
-	/* Process HPD Interrupt */
-	hpd_int_status = HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS);
-	hpd_int_ctrl = HDMI_REG_R(io->base, HDMI_HPD_INT_CTRL);
-	if ((hpd_int_ctrl & BIT(2)) && (hpd_int_status & BIT(0))) {
-		u32 cable_detected = hpd_int_status & BIT(1);
-
+	if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
 		/*
-		 * Clear all interrupts, timer will turn IRQ back on
-		 * Leaving the bit[2] on, else core goes off
-		 * on getting HPD during power off.
+		 * Turn off HPD irq and clear all interrupts,
+		 * worker will turn IRQ back on
 		 */
-		HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, BIT(2) | BIT(0));
-
-		DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
-			hpd_int_ctrl, hpd_int_status);
-
-		mutex_lock(&hdmi_ctrl->mutex);
-		hdmi_ctrl->hpd_cable_chg_detected = true;
-		hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
-		hdmi_ctrl->hpd_stable = 0;
-		mutex_unlock(&hdmi_ctrl->mutex);
-
-		mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
-
-		return IRQ_HANDLED;
+		DSS_REG_W(io, HDMI_HPD_INT_CTRL, ~BIT(2) | BIT(0));
+		queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_int_work);
 	}
 
-	if (!hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
-		return IRQ_HANDLED;
-
-	DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
-		hpd_int_status);
+	if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl) < 0)
+		DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__);
 
 	return IRQ_HANDLED;
 } /* hdmi_tx_isr */
 
-static void hdmi_tx_clk_deinit(struct hdmi_tx_platform_data *pdata)
-{
-	int i;
-	if (!pdata) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return;
-	}
-
-	for (i = HDMI_TX_MAX_CLK - 1; i >= 0; i--) {
-		if (pdata->clk[i])
-			clk_put(pdata->clk[i]);
-		pdata->clk[i] = NULL;
-	}
-} /* hdmi_tx_clk_deinit */
-
-static int hdmi_tx_clk_init(struct platform_device *pdev,
-	struct hdmi_tx_platform_data *pdata)
-{
-	int rc = 0;
-	struct device *dev = NULL;
-	struct clk *clk = NULL;
-
-	if (!pdev || !pdata) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-	dev = &pdev->dev;
-
-	clk = clk_get(dev, "iface_clk");
-	rc = IS_ERR(clk);
-	if (rc) {
-		DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
-		goto error;
-	}
-	pdata->clk[HDMI_TX_AHB_CLK] = clk;
-
-	clk = clk_get(dev, "core_clk");
-	rc = IS_ERR(clk);
-	if (rc) {
-		DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_APP_CLK));
-		goto error;
-	}
-	pdata->clk[HDMI_TX_APP_CLK] = clk;
-
-	clk = clk_get(dev, "extp_clk");
-	rc = IS_ERR(clk);
-	if (rc) {
-		DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
-		goto error;
-	}
-	pdata->clk[HDMI_TX_EXTP_CLK] = clk;
-
-	return rc;
-
-error:
-	hdmi_tx_clk_deinit(pdata);
-	return rc;
-} /* hdmi_tx_clk_init */
-
 static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	if (!hdmi_ctrl) {
@@ -1785,7 +1569,7 @@
 
 	pdata = &hdmi_ctrl->pdata;
 
-	rc = hdmi_tx_check_capability(pdata->io[HDMI_TX_QFPROM_IO].base);
+	rc = hdmi_tx_check_capability(&pdata->io[HDMI_TX_QFPROM_IO]);
 	if (rc) {
 		DEV_ERR("%s: no HDMI device\n", __func__);
 		goto fail_no_hdmi;
@@ -1802,11 +1586,11 @@
 		goto fail_create_workq;
 	}
 
-	/* todo: May be move this ? */
-	hdmi_ctrl->ddc_ctrl.base = pdata->io[HDMI_TX_CORE_IO].base;
+	hdmi_ctrl->ddc_ctrl.io = &pdata->io[HDMI_TX_CORE_IO];
 	init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
 
 	INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
+	INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
 	init_timer(&hdmi_ctrl->hpd_state_timer);
 	hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
 	hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl;
@@ -1868,23 +1652,16 @@
 		return;
 	}
 
-	/* CLK */
-	hdmi_tx_clk_deinit(&hdmi_ctrl->pdata);
-
-	/* VREG */
+	/* VREG & CLK */
 	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--) {
 		if (hdmi_tx_config_power(hdmi_ctrl, i, 0))
 			DEV_ERR("%s: '%s' power deconfig fail\n",
-				__func__, hdmi_pm_name(i));
+				__func__, hdmi_tx_pm_name(i));
 	}
 
 	/* IO */
-	for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) {
-		if (hdmi_ctrl->pdata.io[i].base)
-			iounmap(hdmi_ctrl->pdata.io[i].base);
-		hdmi_ctrl->pdata.io[i].base = NULL;
-		hdmi_ctrl->pdata.io[i].len = 0;
-	}
+	for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--)
+		msm_dss_iounmap(&hdmi_ctrl->pdata.io[i]);
 } /* hdmi_tx_deinit_resource */
 
 static int hdmi_tx_init_resource(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -1913,23 +1690,16 @@
 			pdata->io[i].len);
 	}
 
-	/* VREG */
+	/* VREG & CLK */
 	for (i = 0; i < HDMI_TX_MAX_PM; i++) {
 		rc = hdmi_tx_config_power(hdmi_ctrl, i, 1);
 		if (rc) {
 			DEV_ERR("%s: '%s' power config failed.rc=%d\n",
-				__func__, hdmi_pm_name(i), rc);
+				__func__, hdmi_tx_pm_name(i), rc);
 			goto error;
 		}
 	}
 
-	/* CLK */
-	rc = hdmi_tx_clk_init(hdmi_ctrl->pdev, pdata);
-	if (rc) {
-		DEV_ERR("%s: FAILED: clk init. rc=%d\n", __func__, rc);
-		goto error;
-	}
-
 	return rc;
 
 error:
@@ -1937,6 +1707,98 @@
 	return rc;
 } /* hdmi_tx_init_resource */
 
+static void hdmi_tx_put_dt_clk_data(struct device *dev,
+	struct dss_module_power *module_power)
+{
+	if (!module_power) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (module_power->clk_config) {
+		devm_kfree(dev, module_power->clk_config);
+		module_power->clk_config = NULL;
+	}
+	module_power->num_clk = 0;
+} /* hdmi_tx_put_dt_clk_data */
+
+/* todo: once clk are moved to device tree then change this implementation */
+static int hdmi_tx_get_dt_clk_data(struct device *dev,
+	struct dss_module_power *mp, u32 module_type)
+{
+	int rc = 0;
+
+	if (!dev || !mp) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
+
+	switch (module_type) {
+	case HDMI_TX_HPD_PM:
+		mp->num_clk = 2;
+		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+			mp->num_clk, GFP_KERNEL);
+		if (!mp->clk_config) {
+			DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
+				hdmi_tx_pm_name(module_type));
+			goto error;
+		}
+
+		snprintf(mp->clk_config[0].clk_name, 32, "%s", "iface_clk");
+		mp->clk_config[0].type = DSS_CLK_AHB;
+		mp->clk_config[0].rate = 0;
+
+		snprintf(mp->clk_config[1].clk_name, 32, "%s", "core_clk");
+		mp->clk_config[1].type = DSS_CLK_OTHER;
+		mp->clk_config[1].rate = 19200000;
+		break;
+
+	case HDMI_TX_CORE_PM:
+		mp->num_clk = 2;
+		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+			mp->num_clk, GFP_KERNEL);
+		if (!mp->clk_config) {
+			DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
+				hdmi_tx_pm_name(module_type));
+			goto error;
+		}
+
+		snprintf(mp->clk_config[0].clk_name, 32, "%s", "extp_clk");
+		mp->clk_config[0].type = DSS_CLK_PCLK;
+		/* This rate will be overwritten when core is powered on */
+		mp->clk_config[0].rate = 148500000;
+
+		snprintf(mp->clk_config[1].clk_name, 32, "%s", "alt_iface_clk");
+		mp->clk_config[1].type = DSS_CLK_AHB;
+		mp->clk_config[1].rate = 0;
+		break;
+
+	case HDMI_TX_CEC_PM:
+		mp->num_clk = 0;
+		DEV_DBG("%s: no clk\n", __func__);
+		break;
+
+	default:
+		DEV_ERR("%s: invalid module type=%d\n", __func__,
+			module_type);
+		return -EINVAL;
+	}
+
+	return rc;
+
+error:
+	if (mp->clk_config) {
+		devm_kfree(dev, mp->clk_config);
+		mp->clk_config = NULL;
+	}
+	mp->num_clk = 0;
+
+	return rc;
+} /* hdmi_tx_get_dt_clk_data */
+
 static void hdmi_tx_put_dt_vreg_data(struct device *dev,
 	struct dss_module_power *module_power)
 {
@@ -1985,7 +1847,7 @@
 		return -EINVAL;
 	}
 
-	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
 
 	of_node = dev->of_node;
 
@@ -2025,7 +1887,7 @@
 			mod_vreg_total, GFP_KERNEL);
 		if (!mp->vreg_config) {
 			DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__,
-				hdmi_pm_name(module_type));
+				hdmi_tx_pm_name(module_type));
 			goto error;
 		}
 	} else {
@@ -2070,7 +1932,7 @@
 			prop_name, val_array, dt_vreg_total);
 		if (rc) {
 			DEV_ERR("%s: error read '%s' vreg type. rc=%d\n",
-				__func__, hdmi_pm_name(module_type), rc);
+				__func__, hdmi_tx_pm_name(module_type), rc);
 			goto error;
 		}
 		mp->vreg_config[j].type = val_array[i];
@@ -2085,7 +1947,7 @@
 			dt_vreg_total);
 		if (rc) {
 			DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
-				__func__, hdmi_pm_name(module_type), rc);
+				__func__, hdmi_tx_pm_name(module_type), rc);
 			goto error;
 		}
 		mp->vreg_config[j].min_voltage = val_array[i];
@@ -2100,7 +1962,7 @@
 			dt_vreg_total);
 		if (rc) {
 			DEV_ERR("%s: error read '%s' max volt. rc=%d\n",
-				__func__, hdmi_pm_name(module_type), rc);
+				__func__, hdmi_tx_pm_name(module_type), rc);
 			goto error;
 		}
 		mp->vreg_config[j].max_voltage = val_array[i];
@@ -2115,7 +1977,7 @@
 			dt_vreg_total);
 		if (rc) {
 			DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
-				__func__, hdmi_pm_name(module_type), rc);
+				__func__, hdmi_tx_pm_name(module_type), rc);
 			goto error;
 		}
 		mp->vreg_config[j].optimum_voltage = val_array[i];
@@ -2136,8 +1998,12 @@
 	return rc;
 
 error:
-	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
-		hdmi_tx_put_dt_vreg_data(dev, mp);
+	if (mp->vreg_config) {
+		devm_kfree(dev, mp->vreg_config);
+		mp->vreg_config = NULL;
+	}
+	mp->num_vreg = 0;
+
 	if (val_array)
 		devm_kfree(dev, val_array);
 	return rc;
@@ -2191,7 +2057,7 @@
 		return -EINVAL;
 	}
 
-	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
 
 	of_node = dev->of_node;
 
@@ -2227,7 +2093,7 @@
 			mod_gpio_total, GFP_KERNEL);
 		if (!mp->gpio_config) {
 			DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__,
-				hdmi_pm_name(module_type));
+				hdmi_tx_pm_name(module_type));
 			goto error;
 		}
 	} else {
@@ -2268,8 +2134,11 @@
 	return rc;
 
 error:
-	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
-		hdmi_tx_put_dt_gpio_data(dev, mp);
+	if (mp->gpio_config) {
+		devm_kfree(dev, mp->gpio_config);
+		mp->gpio_config = NULL;
+	}
+	mp->num_gpio = 0;
 
 	return rc;
 } /* hdmi_tx_get_dt_gpio_data */
@@ -2284,6 +2153,9 @@
 	}
 
 	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+		hdmi_tx_put_dt_clk_data(dev, &pdata->power_data[i]);
+
+	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
 		hdmi_tx_put_dt_vreg_data(dev, &pdata->power_data[i]);
 
 	for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
@@ -2317,7 +2189,7 @@
 			&pdata->power_data[i], i);
 		if (rc) {
 			DEV_ERR("%s: '%s' get_dt_gpio_data failed.rc=%d\n",
-				__func__, hdmi_pm_name(i), rc);
+				__func__, hdmi_tx_pm_name(i), rc);
 			goto error;
 		}
 	}
@@ -2328,7 +2200,18 @@
 			&pdata->power_data[i], i);
 		if (rc) {
 			DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n",
-				__func__, hdmi_pm_name(i), rc);
+				__func__, hdmi_tx_pm_name(i), rc);
+			goto error;
+		}
+	}
+
+	/* CLK */
+	for (i = 0; i < HDMI_TX_MAX_PM; i++) {
+		rc = hdmi_tx_get_dt_clk_data(&pdev->dev,
+			&pdata->power_data[i], i);
+		if (rc) {
+			DEV_ERR("%s: '%s' get_dt_clk_data failed.rc=%d\n",
+				__func__, hdmi_tx_pm_name(i), rc);
 			goto error;
 		}
 	}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 7e37d28..94e0fda 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -15,14 +15,6 @@
 
 #include <linux/switch.h>
 #include "mdss_hdmi_util.h"
-#include "mdss_io_util.h"
-
-enum hdmi_tx_clk_type {
-	HDMI_TX_AHB_CLK,
-	HDMI_TX_APP_CLK,
-	HDMI_TX_EXTP_CLK,
-	HDMI_TX_MAX_CLK
-};
 
 enum hdmi_tx_io_type {
 	HDMI_TX_CORE_IO,
@@ -42,9 +34,6 @@
 	/* Data filled from device tree nodes */
 	struct dss_io_data io[HDMI_TX_MAX_IO];
 	struct dss_module_power power_data[HDMI_TX_MAX_PM];
-
-	/* clk and regulator handles */
-	struct clk *clk[HDMI_TX_MAX_CLK];
 };
 
 struct hdmi_tx_ctrl {
@@ -67,6 +56,7 @@
 	u32 hpd_state;
 	u32 hpd_feature_on;
 	struct work_struct hpd_state_work;
+	struct work_struct hpd_int_work;
 	struct timer_list hpd_state_timer;
 
 	unsigned long pixel_clk;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 3ba9f89..e7ea8c9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -15,226 +15,6 @@
 #include <mach/board.h>
 #include "mdss_hdmi_util.h"
 
-const char *hdmi_reg_name(u32 offset)
-{
-	switch (offset) {
-	case 0x00000000: return "HDMI_CTRL";
-	case 0x00000010: return "HDMI_TEST_PATTERN";
-	case 0x00000014: return "HDMI_RANDOM_PATTERN";
-	case 0x00000018: return "HDMI_PKT_BLK_CTRL";
-	case 0x0000001C: return "HDMI_STATUS";
-	case 0x00000020: return "HDMI_AUDIO_PKT_CTRL";
-	case 0x00000024: return "HDMI_ACR_PKT_CTRL";
-	case 0x00000028: return "HDMI_VBI_PKT_CTRL";
-	case 0x0000002C: return "HDMI_INFOFRAME_CTRL0";
-	case 0x00000030: return "HDMI_INFOFRAME_CTRL1";
-	case 0x00000034: return "HDMI_GEN_PKT_CTRL";
-	case 0x0000003C: return "HDMI_ACP";
-	case 0x00000040: return "HDMI_GC";
-	case 0x00000044: return "HDMI_AUDIO_PKT_CTRL2";
-	case 0x00000048: return "HDMI_ISRC1_0";
-	case 0x0000004C: return "HDMI_ISRC1_1";
-	case 0x00000050: return "HDMI_ISRC1_2";
-	case 0x00000054: return "HDMI_ISRC1_3";
-	case 0x00000058: return "HDMI_ISRC1_4";
-	case 0x0000005C: return "HDMI_ISRC2_0";
-	case 0x00000060: return "HDMI_ISRC2_1";
-	case 0x00000064: return "HDMI_ISRC2_2";
-	case 0x00000068: return "HDMI_ISRC2_3";
-	case 0x0000006C: return "HDMI_AVI_INFO0";
-	case 0x00000070: return "HDMI_AVI_INFO1";
-	case 0x00000074: return "HDMI_AVI_INFO2";
-	case 0x00000078: return "HDMI_AVI_INFO3";
-	case 0x0000007C: return "HDMI_MPEG_INFO0";
-	case 0x00000080: return "HDMI_MPEG_INFO1";
-	case 0x00000084: return "HDMI_GENERIC0_HDR";
-	case 0x00000088: return "HDMI_GENERIC0_0";
-	case 0x0000008C: return "HDMI_GENERIC0_1";
-	case 0x00000090: return "HDMI_GENERIC0_2";
-	case 0x00000094: return "HDMI_GENERIC0_3";
-	case 0x00000098: return "HDMI_GENERIC0_4";
-	case 0x0000009C: return "HDMI_GENERIC0_5";
-	case 0x000000A0: return "HDMI_GENERIC0_6";
-	case 0x000000A4: return "HDMI_GENERIC1_HDR";
-	case 0x000000A8: return "HDMI_GENERIC1_0";
-	case 0x000000AC: return "HDMI_GENERIC1_1";
-	case 0x000000B0: return "HDMI_GENERIC1_2";
-	case 0x000000B4: return "HDMI_GENERIC1_3";
-	case 0x000000B8: return "HDMI_GENERIC1_4";
-	case 0x000000BC: return "HDMI_GENERIC1_5";
-	case 0x000000C0: return "HDMI_GENERIC1_6";
-	case 0x000000C4: return "HDMI_ACR_32_0";
-	case 0x000000C8: return "HDMI_ACR_32_1";
-	case 0x000000CC: return "HDMI_ACR_44_0";
-	case 0x000000D0: return "HDMI_ACR_44_1";
-	case 0x000000D4: return "HDMI_ACR_48_0";
-	case 0x000000D8: return "HDMI_ACR_48_1";
-	case 0x000000DC: return "HDMI_ACR_STATUS_0";
-	case 0x000000E0: return "HDMI_ACR_STATUS_1";
-	case 0x000000E4: return "HDMI_AUDIO_INFO0";
-	case 0x000000E8: return "HDMI_AUDIO_INFO1";
-	case 0x000000EC: return "HDMI_CS_60958_0";
-	case 0x000000F0: return "HDMI_CS_60958_1";
-	case 0x000000F8: return "HDMI_RAMP_CTRL0";
-	case 0x000000FC: return "HDMI_RAMP_CTRL1";
-	case 0x00000100: return "HDMI_RAMP_CTRL2";
-	case 0x00000104: return "HDMI_RAMP_CTRL3";
-	case 0x00000108: return "HDMI_CS_60958_2";
-	case 0x00000110: return "HDMI_HDCP_CTRL";
-	case 0x00000114: return "HDMI_HDCP_DEBUG_CTRL";
-	case 0x00000118: return "HDMI_HDCP_INT_CTRL";
-	case 0x0000011C: return "HDMI_HDCP_LINK0_STATUS";
-	case 0x00000120: return "HDMI_HDCP_DDC_CTRL_0";
-	case 0x00000124: return "HDMI_HDCP_DDC_CTRL_1";
-	case 0x00000128: return "HDMI_HDCP_DDC_STATUS";
-	case 0x0000012C: return "HDMI_HDCP_ENTROPY_CTRL0";
-	case 0x00000130: return "HDMI_HDCP_RESET";
-	case 0x00000134: return "HDMI_HDCP_RCVPORT_DATA0";
-	case 0x00000138: return "HDMI_HDCP_RCVPORT_DATA1";
-	case 0x0000013C: return "HDMI_HDCP_RCVPORT_DATA2_0";
-	case 0x00000140: return "HDMI_HDCP_RCVPORT_DATA2_1";
-	case 0x00000144: return "HDMI_HDCP_RCVPORT_DATA3";
-	case 0x00000148: return "HDMI_HDCP_RCVPORT_DATA4";
-	case 0x0000014C: return "HDMI_HDCP_RCVPORT_DATA5";
-	case 0x00000150: return "HDMI_HDCP_RCVPORT_DATA6";
-	case 0x00000154: return "HDMI_HDCP_RCVPORT_DATA7";
-	case 0x00000158: return "HDMI_HDCP_RCVPORT_DATA8";
-	case 0x0000015C: return "HDMI_HDCP_RCVPORT_DATA9";
-	case 0x00000160: return "HDMI_HDCP_RCVPORT_DATA10";
-	case 0x00000164: return "HDMI_HDCP_RCVPORT_DATA11";
-	case 0x00000168: return "HDMI_HDCP_RCVPORT_DATA12";
-	case 0x0000016C: return "HDMI_VENSPEC_INFO0";
-	case 0x00000170: return "HDMI_VENSPEC_INFO1";
-	case 0x00000174: return "HDMI_VENSPEC_INFO2";
-	case 0x00000178: return "HDMI_VENSPEC_INFO3";
-	case 0x0000017C: return "HDMI_VENSPEC_INFO4";
-	case 0x00000180: return "HDMI_VENSPEC_INFO5";
-	case 0x00000184: return "HDMI_VENSPEC_INFO6";
-	case 0x00000194: return "HDMI_HDCP_DEBUG";
-	case 0x0000019C: return "HDMI_TMDS_CTRL_CHAR";
-	case 0x000001A4: return "HDMI_TMDS_CTRL_SEL";
-	case 0x000001A8: return "HDMI_TMDS_SYNCCHAR01";
-	case 0x000001AC: return "HDMI_TMDS_SYNCCHAR23";
-	case 0x000001B4: return "HDMI_TMDS_DEBUG";
-	case 0x000001B8: return "HDMI_TMDS_CTL_BITS";
-	case 0x000001BC: return "HDMI_TMDS_DCBAL_CTRL";
-	case 0x000001C0: return "HDMI_TMDS_DCBAL_CHAR";
-	case 0x000001C8: return "HDMI_TMDS_CTL01_GEN";
-	case 0x000001CC: return "HDMI_TMDS_CTL23_GEN";
-	case 0x000001D0: return "HDMI_AUDIO_CFG";
-	case 0x00000204: return "HDMI_DEBUG";
-	case 0x00000208: return "HDMI_USEC_REFTIMER";
-	case 0x0000020C: return "HDMI_DDC_CTRL";
-	case 0x00000210: return "HDMI_DDC_ARBITRATION";
-	case 0x00000214: return "HDMI_DDC_INT_CTRL";
-	case 0x00000218: return "HDMI_DDC_SW_STATUS";
-	case 0x0000021C: return "HDMI_DDC_HW_STATUS";
-	case 0x00000220: return "HDMI_DDC_SPEED";
-	case 0x00000224: return "HDMI_DDC_SETUP";
-	case 0x00000228: return "HDMI_DDC_TRANS0";
-	case 0x0000022C: return "HDMI_DDC_TRANS1";
-	case 0x00000230: return "HDMI_DDC_TRANS2";
-	case 0x00000234: return "HDMI_DDC_TRANS3";
-	case 0x00000238: return "HDMI_DDC_DATA";
-	case 0x0000023C: return "HDMI_HDCP_SHA_CTRL";
-	case 0x00000240: return "HDMI_HDCP_SHA_STATUS";
-	case 0x00000244: return "HDMI_HDCP_SHA_DATA";
-	case 0x00000248: return "HDMI_HDCP_SHA_DBG_M0_0";
-	case 0x0000024C: return "HDMI_HDCP_SHA_DBG_M0_1";
-	case 0x00000250: return "HDMI_HPD_INT_STATUS";
-	case 0x00000254: return "HDMI_HPD_INT_CTRL";
-	case 0x00000258: return "HDMI_HPD_CTRL";
-	case 0x0000025C: return "HDMI_HDCP_ENTROPY_CTRL1";
-	case 0x00000260: return "HDMI_HDCP_SW_UPPER_AN";
-	case 0x00000264: return "HDMI_HDCP_SW_LOWER_AN";
-	case 0x00000268: return "HDMI_CRC_CTRL";
-	case 0x0000026C: return "HDMI_VID_CRC";
-	case 0x00000270: return "HDMI_AUD_CRC";
-	case 0x00000274: return "HDMI_VBI_CRC";
-	case 0x0000027C: return "HDMI_DDC_REF";
-	case 0x00000284: return "HDMI_HDCP_SW_UPPER_AKSV";
-	case 0x00000288: return "HDMI_HDCP_SW_LOWER_AKSV";
-	case 0x0000028C: return "HDMI_CEC_CTRL";
-	case 0x00000290: return "HDMI_CEC_WR_DATA";
-	case 0x00000294: return "HDMI_CEC_RETRANSMIT";
-	case 0x00000298: return "HDMI_CEC_STATUS";
-	case 0x0000029C: return "HDMI_CEC_INT";
-	case 0x000002A0: return "HDMI_CEC_ADDR";
-	case 0x000002A4: return "HDMI_CEC_TIME";
-	case 0x000002A8: return "HDMI_CEC_REFTIMER";
-	case 0x000002AC: return "HDMI_CEC_RD_DATA";
-	case 0x000002B0: return "HDMI_CEC_RD_FILTER";
-	case 0x000002B4: return "HDMI_ACTIVE_H";
-	case 0x000002B8: return "HDMI_ACTIVE_V";
-	case 0x000002BC: return "HDMI_ACTIVE_V_F2";
-	case 0x000002C0: return "HDMI_TOTAL";
-	case 0x000002C4: return "HDMI_V_TOTAL_F2";
-	case 0x000002C8: return "HDMI_FRAME_CTRL";
-	case 0x000002CC: return "HDMI_AUD_INT";
-	case 0x000002D0: return "HDMI_DEBUG_BUS_CTRL";
-	case 0x000002D4: return "HDMI_PHY_CTRL";
-	case 0x000002DC: return "HDMI_CEC_WR_RANGE";
-	case 0x000002E0: return "HDMI_CEC_RD_RANGE";
-	case 0x000002E4: return "HDMI_VERSION";
-	case 0x000002F4: return "HDMI_BIST_ENABLE";
-	case 0x000002F8: return "HDMI_TIMING_ENGINE_EN";
-	case 0x000002FC: return "HDMI_INTF_CONFIG";
-	case 0x00000300: return "HDMI_HSYNC_CTL";
-	case 0x00000304: return "HDMI_VSYNC_PERIOD_F0";
-	case 0x00000308: return "HDMI_VSYNC_PERIOD_F1";
-	case 0x0000030C: return "HDMI_VSYNC_PULSE_WIDTH_F0";
-	case 0x00000310: return "HDMI_VSYNC_PULSE_WIDTH_F1";
-	case 0x00000314: return "HDMI_DISPLAY_V_START_F0";
-	case 0x00000318: return "HDMI_DISPLAY_V_START_F1";
-	case 0x0000031C: return "HDMI_DISPLAY_V_END_F0";
-	case 0x00000320: return "HDMI_DISPLAY_V_END_F1";
-	case 0x00000324: return "HDMI_ACTIVE_V_START_F0";
-	case 0x00000328: return "HDMI_ACTIVE_V_START_F1";
-	case 0x0000032C: return "HDMI_ACTIVE_V_END_F0";
-	case 0x00000330: return "HDMI_ACTIVE_V_END_F1";
-	case 0x00000334: return "HDMI_DISPLAY_HCTL";
-	case 0x00000338: return "HDMI_ACTIVE_HCTL";
-	case 0x0000033C: return "HDMI_HSYNC_SKEW";
-	case 0x00000340: return "HDMI_POLARITY_CTL";
-	case 0x00000344: return "HDMI_TPG_MAIN_CONTROL";
-	case 0x00000348: return "HDMI_TPG_VIDEO_CONFIG";
-	case 0x0000034C: return "HDMI_TPG_COMPONENT_LIMITS";
-	case 0x00000350: return "HDMI_TPG_RECTANGLE";
-	case 0x00000354: return "HDMI_TPG_INITIAL_VALUE";
-	case 0x00000358: return "HDMI_TPG_BLK_WHT_PATTERN_FRAMES";
-	case 0x0000035C: return "HDMI_TPG_RGB_MAPPING";
-	default: return "???";
-	}
-} /* hdmi_reg_name */
-
-void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug)
-{
-	u32 in_val;
-
-	writel_relaxed(value, addr+offset);
-	if (debug && PORT_DEBUG) {
-		in_val = readl_relaxed(addr+offset);
-		DEV_DBG("HDMI[%04x] => %08x [%08x] %s\n", offset, value,
-			in_val, hdmi_reg_name(offset));
-	}
-} /* hdmi_reg_w */
-
-u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug)
-{
-	u32 value = readl_relaxed(addr+offset);
-	if (debug && PORT_DEBUG)
-		DEV_DBG("HDMI[%04x] <= %08x %s\n", offset, value,
-			hdmi_reg_name(offset));
-	return value;
-} /* hdmi_reg_r */
-
-void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix)
-{
-	if (REG_DUMP)
-		print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
-			(void *)base, length, false);
-} /* hdmi_reg_dump */
-
 static struct hdmi_disp_mode_timing_type
 	hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
 	HDMI_SETTINGS_640x480p60_4_3,
@@ -505,7 +285,7 @@
 {
 	u32 reg_val, time_out_count;
 
-	if (!ddc_ctrl || !ddc_ctrl->base) {
+	if (!ddc_ctrl || !ddc_ctrl->io) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
@@ -515,9 +295,9 @@
 	do {
 		--time_out_count;
 		/* Clear and Enable DDC interrupt */
-		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
 			BIT(2) | BIT(1));
-		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+		reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
 	} while ((reg_val & BIT(0)) && time_out_count);
 
 	if (!time_out_count) {
@@ -535,7 +315,7 @@
 	int status = 0;
 	int log_retry_fail;
 
-	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+	if (!ddc_ctrl || !ddc_ctrl->io || !ddc_data) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
@@ -565,7 +345,7 @@
 	 *    INDEX = 0x0 (initial offset into buffer)
 	 *    INDEX_WRITE = 0x1 (setting initial offset)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 		BIT(31) | (ddc_data->dev_addr << 8));
 
 	/*
@@ -576,7 +356,7 @@
 	 *    INDEX = 0x0
 	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8);
 
 	/*
 	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -586,7 +366,7 @@
 	 *    INDEX = 0x0
 	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 		(ddc_data->dev_addr | BIT(0)) << 8);
 
 	/* Data setup is complete, now setup the transaction characteristics */
@@ -599,7 +379,7 @@
 	 *    STOP0 = 0x0 (do NOT insert STOP bit)
 	 *    CNT0 = 0x1 (single byte transaction excluding address)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
 
 	/*
 	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -609,7 +389,7 @@
 	 *    STOP1 = 0x1 (insert STOP bit)
 	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1,
 		BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
 
 	/* Trigger the I2C transfer */
@@ -624,11 +404,11 @@
 	 *    GO = 0x1 (kicks off hardware)
 	 */
 	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
 
 	time_out_count = wait_for_completion_interruptible_timeout(
 		&ddc_ctrl->ddc_sw_done, HZ/2);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, BIT(1));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, BIT(1));
 	if (!time_out_count) {
 		if (ddc_data->retry-- > 0) {
 			DEV_INFO("%s: failed timout, retry=%d\n", __func__,
@@ -637,26 +417,26 @@
 		}
 		status = -ETIMEDOUT;
 		DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL));
 		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
 			__func__,
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS),
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS));
 		goto error;
 	}
 
 	/* Read DDC status */
-	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS);
 	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
 
 	/* Check if any NACK occurred */
 	if (reg_val) {
 		/* SW_STATUS_RESET */
-		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3));
 
 		if (ddc_data->retry == 1)
 			/* SOFT_RESET */
-			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+			DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1));
 
 		if (ddc_data->retry-- > 0) {
 			DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
@@ -687,13 +467,13 @@
 	 *    INDEX_WRITE = 0x1 (explicitly define offset)
 	 */
 	/* Write this data to DDC buffer */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 		BIT(0) | (3 << 16) | BIT(31));
 
 	/* Discard first byte */
-	HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+	DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
 	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
-		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+		reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
 		ddc_data->data_buf[ndx] = (u8)((reg_val & 0x0000FF00) >> 8);
 	}
 
@@ -705,46 +485,44 @@
 
 void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
 {
-	if (!ddc_ctrl || !ddc_ctrl->base) {
+	if (!ddc_ctrl || !ddc_ctrl->io) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return;
 	}
 
 	/* Configure Pre-Scale multiplier & Threshold */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
 
 	/*
 	 * Setting 31:24 bits : Time units to wait before timeout
 	 * when clock is being stalled by external sink device
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SETUP, 0xFF000000);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_SETUP, 0xFF000000);
 
 	/* Enable reference timer to 27 micro-seconds */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (27 << 0));
 } /* hdmi_ddc_config */
 
 int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
 {
-	int rc = -1;
 	u32 ddc_int_ctrl;
 
-	if (!ddc_ctrl || !ddc_ctrl->base) {
+	if (!ddc_ctrl || !ddc_ctrl->io) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
 
-	ddc_int_ctrl = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	ddc_int_ctrl = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
 	if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) {
 		/* SW_DONE INT occured, clr it */
-		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
 			ddc_int_ctrl | BIT(1));
 		complete(&ddc_ctrl->ddc_sw_done);
-		return 0;
 	}
 
 	DEV_DBG("%s: ddc_int_ctrl=%04x\n", __func__, ddc_int_ctrl);
 
-	return rc;
+	return 0;
 } /* hdmi_ddc_isr */
 
 int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
@@ -779,7 +557,7 @@
 	int log_retry_fail;
 	int seg_addr = 0x60, seg_num = 0x01;
 
-	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+	if (!ddc_ctrl || !ddc_ctrl->io || !ddc_data) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
@@ -808,7 +586,7 @@
 	 *    INDEX = 0x0 (initial offset into buffer)
 	 *    INDEX_WRITE = 0x1 (setting initial offset)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
 
 	/*
 	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -818,7 +596,7 @@
 	 *    INDEX = 0x0
 	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, seg_num << 8);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, seg_num << 8);
 
 	/*
 	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -828,9 +606,9 @@
 	 *    INDEX = 0x0
 	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 		(ddc_data->dev_addr | BIT(0)) << 8);
 
 	/* Data setup is complete, now setup the transaction characteristics */
@@ -843,7 +621,7 @@
 	 *    STOP0 = 0x0 (do NOT insert STOP bit)
 	 *    CNT0 = 0x1 (single byte transaction excluding address)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
 
 	/*
 	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -853,7 +631,7 @@
 	 *    STOP1 = 0x1 (insert STOP bit)
 	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
 
 	/*
 	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -863,7 +641,7 @@
 	 *    STOP1 = 0x1 (insert STOP bit)
 	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS2,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS2,
 		BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
 
 	/* Trigger the I2C transfer */
@@ -877,13 +655,13 @@
 	 *    GO = 0x1 (kicks off hardware)
 	 */
 	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(21));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(21));
 
 	time_out_count = wait_for_completion_interruptible_timeout(
 		&ddc_ctrl->ddc_sw_done, HZ/2);
 
-	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+	reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
 	if (!time_out_count) {
 		if (ddc_data->retry-- > 0) {
 			DEV_INFO("%s: failed timout, retry=%d\n", __func__,
@@ -892,25 +670,25 @@
 		}
 		status = -ETIMEDOUT;
 		DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL));
 		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
 			__func__,
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS),
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS));
 		goto error;
 	}
 
 	/* Read DDC status */
-	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS);
 	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
 
 	/* Check if any NACK occurred */
 	if (reg_val) {
 		/* SW_STATUS_RESET */
-		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3));
 		if (ddc_data->retry == 1)
 			/* SOFT_RESET */
-			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+			DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1));
 		if (ddc_data->retry-- > 0) {
 			DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
 				__func__, ddc_data->what, reg_val,
@@ -940,14 +718,14 @@
 	 *    INDEX_WRITE = 0x1 (explicitly define offset)
 	 */
 	/* Write this data to DDC buffer */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 		BIT(0) | (5 << 16) | BIT(31));
 
 	/* Discard first byte */
-	HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+	DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
 
 	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
-		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+		reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
 		ddc_data->data_buf[ndx] = (u8) ((reg_val & 0x0000FF00) >> 8);
 	}
 
@@ -964,7 +742,7 @@
 	int status = 0, retry = 10;
 	u32 time_out_count;
 
-	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+	if (!ddc_ctrl || !ddc_ctrl->io || !ddc_data) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
@@ -991,7 +769,7 @@
 	 *    INDEX = 0x0 (initial offset into buffer)
 	 *    INDEX_WRITE = 0x1 (setting initial offset)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 		BIT(31) | (ddc_data->dev_addr << 8));
 
 	/*
@@ -1002,7 +780,7 @@
 	 *    INDEX = 0x0
 	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8);
 
 	/*
 	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -1013,7 +791,7 @@
 	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
 	 */
 	for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
-		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
 			((u32)ddc_data->data_buf[ndx]) << 8);
 
 	/* Data setup is complete, now setup the transaction characteristics */
@@ -1026,7 +804,7 @@
 	 *    STOP0 = 0x0 (do NOT insert STOP bit)
 	 *    CNT0 = 0x1 (single byte transaction excluding address)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
 
 	/*
 	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -1038,7 +816,7 @@
 	 *    Byte count for second transition (excluding the first
 	 *    Byte which is usually the address)
 	 */
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1,
 		BIT(13) | ((ddc_data->data_len-1) << 16));
 
 	/* Trigger the I2C transfer */
@@ -1051,13 +829,13 @@
 	 *    GO = 0x1 (kicks off hardware)
 	 */
 	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
 
 	time_out_count = wait_for_completion_interruptible_timeout(
 		&ddc_ctrl->ddc_sw_done, HZ/2);
 
-	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
-	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+	reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
 	if (!time_out_count) {
 		if (retry-- > 0) {
 			DEV_INFO("%s[%s]: failed timout, retry=%d\n", __func__,
@@ -1067,26 +845,26 @@
 		status = -ETIMEDOUT;
 		DEV_ERR("%s[%s]: timedout, Int Ctrl=%08x\n",
 			__func__, ddc_data->what,
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL));
 		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
 			__func__,
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
-			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS),
+			DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS));
 		goto error;
 	}
 
 	/* Read DDC status */
-	reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_SW_STATUS);
 	reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000;
 
 	/* Check if any NACK occurred */
 	if (reg_val) {
 		if (retry > 1)
 			/* SW_STATUS_RESET */
-			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+			DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3));
 		else
 			/* SOFT_RESET */
-			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+			DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1));
 
 		if (retry-- > 0) {
 			DEV_DBG("%s[%s]: failed NACK=%08x, retry=%d\n",
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index 47515ba..852a93c 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -12,26 +12,7 @@
 
 #ifndef __HDMI_UTIL_H__
 #define __HDMI_UTIL_H__
-
-#define DEV_INFO(fmt, args...)	pr_info(fmt, ##args)
-#define DEV_WARN(fmt, args...)	pr_warn(fmt, ##args)
-#define DEV_ERR(fmt, args...)	pr_err(fmt, ##args)
-
-#ifdef DEBUG
-#define DEV_DBG(fmt, args...)	pr_err(fmt, ##args)
-#else
-#define DEV_DBG(args...)	(void)0
-#endif
-
-#define PORT_DEBUG 0
-#define REG_DUMP 0
-void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug);
-u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug);
-
-#define HDMI_REG_W_ND(addr, offset, val)  hdmi_reg_w(addr, offset, val, false)
-#define HDMI_REG_W(addr, offset, val)     hdmi_reg_w(addr, offset, val, true)
-#define HDMI_REG_R_ND(addr, offset)       hdmi_reg_r(addr, offset, false)
-#define HDMI_REG_R(addr, offset)          hdmi_reg_r(addr, offset, true)
+#include "mdss_io_util.h"
 
 /* HDMI_TX Registers */
 #define HDMI_CTRL                        (0x00000000)
@@ -220,7 +201,7 @@
 #define HDMI_TPG_BLK_WHT_PATTERN_FRAMES  (0x00000358)
 #define HDMI_TPG_RGB_MAPPING             (0x0000035C)
 
-/* HDMI PHY Registers, use them with PHY base and _ND macro */
+/* HDMI PHY Registers */
 #define HDMI_PHY_ANA_CFG0                (0x00000000)
 #define HDMI_PHY_ANA_CFG1                (0x00000004)
 #define HDMI_PHY_PD_CTRL0                (0x00000010)
@@ -231,6 +212,10 @@
 #define HDMI_PHY_BIST_PATN2              (0x00000044)
 #define HDMI_PHY_BIST_PATN3              (0x00000048)
 
+/* QFPROM Registers for HDMI/HDCP */
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB  (0x000000F8)
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB  (0x000000FC)
+
 /* all video formats defined by EIA CEA 861D */
 #define HDMI_VFRMT_640x480p60_4_3	0
 #define HDMI_VFRMT_720x480p60_4_3	1
@@ -397,7 +382,7 @@
 };
 
 struct hdmi_tx_ddc_ctrl {
-	void __iomem *base;
+	struct dss_io_data *io;
 	struct completion ddc_sw_done;
 };
 
@@ -412,9 +397,6 @@
 	int retry;
 };
 
-void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix);
-const char *hdmi_reg_name(u32 offset);
-
 const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
 void hdmi_set_supported_mode(u32 mode);
 const char *hdmi_get_video_fmt_2string(u32 format);
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 65d08d3..5778525 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -10,10 +10,65 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include "mdss_io_util.h"
 
+void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
+{
+	u32 in_val;
+
+	if (!io || !io->base) {
+		DEV_ERR("%pS->%s: invalid input\n",
+			__builtin_return_address(0), __func__);
+		return;
+	}
+
+	if (offset > io->len) {
+		DEV_ERR("%pS->%s: offset out of range\n",
+			__builtin_return_address(0), __func__);
+		return;
+	}
+
+	writel_relaxed(value, io->base + offset);
+	if (debug) {
+		in_val = readl_relaxed(io->base + offset);
+		DEV_DBG("[%08x] => %08x [%08x]\n", (u32)(io->base + offset),
+			value, in_val);
+	}
+} /* dss_reg_w */
+
+u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug)
+{
+	u32 value;
+	if (!io || !io->base) {
+		DEV_ERR("%pS->%s: invalid input\n",
+			__builtin_return_address(0), __func__);
+		return -EINVAL;
+	}
+
+	if (offset > io->len) {
+		DEV_ERR("%pS->%s: offset out of range\n",
+			__builtin_return_address(0), __func__);
+		return -EINVAL;
+	}
+
+	value = readl_relaxed(io->base + offset);
+	if (debug)
+		DEV_DBG("[%08x] <= %08x\n", (u32)(io->base + offset), value);
+
+	return value;
+} /* dss_reg_r */
+
+void dss_reg_dump(void __iomem *base, u32 length, const char *prefix,
+	u32 debug)
+{
+	if (debug)
+		print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
+			(void *)base, length, false);
+} /* dss_reg_dump */
+
 static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
 	unsigned int type, const char *name)
 {
@@ -21,11 +76,10 @@
 
 	res = platform_get_resource_byname(pdev, type, name);
 	if (!res)
-		pr_err("%s: '%s' resource not found\n", __func__, name);
+		DEV_ERR("%s: '%s' resource not found\n", __func__, name);
 
 	return res;
-}
-
+} /* msm_dss_get_res_byname */
 
 int msm_dss_ioremap_byname(struct platform_device *pdev,
 	struct dss_io_data *io_data, const char *name)
@@ -33,32 +87,49 @@
 	struct resource *res = NULL;
 
 	if (!pdev || !io_data) {
-		pr_err("%s: invalid input\n", __func__);
+		DEV_ERR("%pS->%s: invalid input\n",
+			__builtin_return_address(0), __func__);
 		return -EINVAL;
 	}
 
 	res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
 	if (!res) {
-		pr_err("%s: '%s' msm_dss_get_res_byname failed\n",
-			__func__, name);
+		DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n",
+			__builtin_return_address(0), __func__, name);
 		return -ENODEV;
 	}
 
 	io_data->len = resource_size(res);
 	io_data->base = ioremap(res->start, io_data->len);
 	if (!io_data->base) {
-		pr_err("%s: '%s' ioremap failed\n", __func__, name);
+		DEV_ERR("%pS->%s: '%s' ioremap failed\n",
+			__builtin_return_address(0), __func__, name);
 		return -EIO;
 	}
 
 	return 0;
-}
+} /* msm_dss_ioremap_byname */
+
+void msm_dss_iounmap(struct dss_io_data *io_data)
+{
+	if (!io_data) {
+		DEV_ERR("%pS->%s: invalid input\n",
+			__builtin_return_address(0), __func__);
+		return;
+	}
+
+	if (io_data->base) {
+		iounmap(io_data->base);
+		io_data->base = NULL;
+	}
+	io_data->len = 0;
+} /* msm_dss_iounmap */
 
 int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
 	int num_vreg, int config)
 {
 	int i = 0, rc = 0;
-	struct dss_vreg *curr_vreg;
+	struct dss_vreg *curr_vreg = NULL;
 
 	if (config) {
 		for (i = 0; i < num_vreg; i++) {
@@ -67,8 +138,8 @@
 				curr_vreg->vreg_name);
 			rc = IS_ERR(curr_vreg->vreg);
 			if (rc) {
-				pr_err("%s: %s get failed. rc=%d\n",
-					 __func__,
+				DEV_ERR("%pS->%s: %s get failed. rc=%d\n",
+					 __builtin_return_address(0), __func__,
 					 curr_vreg->vreg_name, rc);
 				curr_vreg->vreg = NULL;
 				goto vreg_get_fail;
@@ -79,7 +150,8 @@
 					curr_vreg->min_voltage,
 					curr_vreg->max_voltage);
 				if (rc < 0) {
-					pr_err("%s: %s set voltage failed\n",
+					DEV_ERR("%pS->%s: %s set vltg fail\n",
+						__builtin_return_address(0),
 						__func__,
 						curr_vreg->vreg_name);
 					goto vreg_set_voltage_fail;
@@ -89,8 +161,9 @@
 						curr_vreg->vreg,
 						curr_vreg->optimum_voltage);
 					if (rc < 0) {
-						pr_err(
-						"%s: %s set opt mode failed\n",
+						DEV_ERR(
+						"%pS->%s: %s set opt m fail\n",
+						__builtin_return_address(0),
 						__func__,
 						curr_vreg->vreg_name);
 						goto vreg_set_opt_mode_fail;
@@ -144,14 +217,16 @@
 		for (i = 0; i < num_vreg; i++) {
 			rc = IS_ERR(in_vreg[i].vreg);
 			if (rc) {
-				pr_err("%s: %s regulator error. rc=%d\n",
-					__func__, in_vreg[i].vreg_name, rc);
+				DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
+					__builtin_return_address(0), __func__,
+					in_vreg[i].vreg_name, rc);
 				goto disable_vreg;
 			}
 			rc = regulator_enable(in_vreg[i].vreg);
 			if (rc < 0) {
-				pr_err("%s: %s enable failed\n",
-					__func__, in_vreg[i].vreg_name);
+				DEV_ERR("%pS->%s: %s enable failed\n",
+					__builtin_return_address(0), __func__,
+					in_vreg[i].vreg_name);
 				goto disable_vreg;
 			}
 		}
@@ -176,8 +251,9 @@
 			rc = gpio_request(in_gpio[i].gpio,
 				in_gpio[i].gpio_name);
 			if (rc < 0) {
-				pr_err("%s: %s enable failed\n",
-					__func__, in_gpio[i].gpio_name);
+				DEV_ERR("%pS->%s: %s enable failed\n",
+					__builtin_return_address(0), __func__,
+					in_gpio[i].gpio_name);
 				goto disable_gpio;
 			}
 		}
@@ -192,3 +268,117 @@
 		gpio_free(in_gpio[i].gpio);
 	return rc;
 } /* msm_dss_enable_gpio */
+
+void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
+{
+	int i;
+
+	for (i = num_clk - 1; i >= 0; i--) {
+		if (clk_arry[i].clk)
+			clk_put(clk_arry[i].clk);
+		clk_arry[i].clk = NULL;
+	}
+} /* msm_dss_put_clk */
+
+int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < num_clk; i++) {
+		clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
+		rc = IS_ERR(clk_arry[i].clk);
+		if (rc) {
+			DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
+				__builtin_return_address(0), __func__,
+				clk_arry[i].clk_name, rc);
+			goto error;
+		}
+	}
+
+	return rc;
+
+error:
+	msm_dss_put_clk(clk_arry, num_clk);
+
+	return rc;
+} /* msm_dss_get_clk */
+
+int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < num_clk; i++) {
+		if (clk_arry[i].clk) {
+			if (DSS_CLK_AHB != clk_arry[i].type) {
+				DEV_DBG("%pS->%s: '%s' rate %ld\n",
+					__builtin_return_address(0), __func__,
+					clk_arry[i].clk_name,
+					clk_arry[i].rate);
+				rc = clk_set_rate(clk_arry[i].clk,
+					clk_arry[i].rate);
+				if (rc) {
+					DEV_ERR("%pS->%s: %s failed. rc=%d\n",
+						__builtin_return_address(0),
+						__func__,
+						clk_arry[i].clk_name, rc);
+					break;
+				}
+			}
+		} else {
+			DEV_ERR("%pS->%s: '%s' is not available\n",
+				__builtin_return_address(0), __func__,
+				clk_arry[i].clk_name);
+			rc = -EPERM;
+			break;
+		}
+	}
+
+	return rc;
+} /* msm_dss_clk_set_rate */
+
+int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
+{
+	int i, rc = 0;
+
+	if (enable) {
+		for (i = 0; i < num_clk; i++) {
+			DEV_DBG("%pS->%s: enable '%s'\n",
+				__builtin_return_address(0), __func__,
+				clk_arry[i].clk_name);
+			if (clk_arry[i].clk) {
+				rc = clk_prepare_enable(clk_arry[i].clk);
+				if (rc)
+					DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
+						__builtin_return_address(0),
+						__func__,
+						clk_arry[i].clk_name, rc);
+			} else {
+				DEV_ERR("%pS->%s: '%s' is not available\n",
+					__builtin_return_address(0), __func__,
+					clk_arry[i].clk_name);
+				rc = -EPERM;
+			}
+
+			if (rc) {
+				msm_dss_enable_clk(&clk_arry[i],
+					i, false);
+				break;
+			}
+		}
+	} else {
+		for (i = num_clk - 1; i >= 0; i--) {
+			DEV_DBG("%pS->%s: disable '%s'\n",
+				__builtin_return_address(0), __func__,
+				clk_arry[i].clk_name);
+
+			if (clk_arry[i].clk)
+				clk_disable_unprepare(clk_arry[i].clk);
+			else
+				DEV_ERR("%pS->%s: '%s' is not available\n",
+					__builtin_return_address(0), __func__,
+					clk_arry[i].clk_name);
+		}
+	}
+
+	return rc;
+} /* msm_dss_enable_clk */
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index 9671414..51e9e54 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -17,11 +17,29 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
+#ifdef DEBUG
+#define DEV_DBG(fmt, args...)   pr_err(fmt, ##args)
+#else
+#define DEV_DBG(fmt, args...)   pr_debug(fmt, ##args)
+#endif
+#define DEV_INFO(fmt, args...)  pr_info(fmt, ##args)
+#define DEV_WARN(fmt, args...)  pr_warn(fmt, ##args)
+#define DEV_ERR(fmt, args...)   pr_err(fmt, ##args)
+
 struct dss_io_data {
 	u32 len;
 	void __iomem *base;
 };
 
+void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug);
+u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug);
+void dss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
+
+#define DSS_REG_W_ND(io, offset, val)  dss_reg_w(io, offset, val, false)
+#define DSS_REG_W(io, offset, val)     dss_reg_w(io, offset, val, true)
+#define DSS_REG_R_ND(io, offset)       dss_reg_r(io, offset, false)
+#define DSS_REG_R(io, offset)          dss_reg_r(io, offset, true)
+
 enum dss_vreg_type {
 	DSS_REG_LDO,
 	DSS_REG_VS,
@@ -41,19 +59,42 @@
 	char gpio_name[32];
 };
 
+enum dss_clk_type {
+	DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
+	DSS_CLK_PCLK,
+	DSS_CLK_OTHER,
+};
+
+struct dss_clk {
+	struct clk *clk; /* clk handle */
+	char clk_name[32];
+	enum dss_clk_type type;
+	unsigned long rate;
+};
+
 struct dss_module_power {
 	unsigned num_vreg;
 	struct dss_vreg *vreg_config;
 	unsigned num_gpio;
 	struct dss_gpio *gpio_config;
+	unsigned num_clk;
+	struct dss_clk *clk_config;
 };
 
 int msm_dss_ioremap_byname(struct platform_device *pdev,
 	struct dss_io_data *io_data, const char *name);
+void msm_dss_iounmap(struct dss_io_data *io_data);
+
 int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
 int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
+
 int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
 	int num_vreg, int config);
 int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg,	int enable);
 
+int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
+void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
+int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
+int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
+
 #endif /* __MDSS_IO_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 20fce7c..0f6cfe9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -218,8 +218,9 @@
 
 	spin_lock_irqsave(&mdss_lock, irq_flags);
 	if (!(mdss_res->irq_mask & ndx_bit)) {
-		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
-			hw->hw_ndx, mdss_res->mdp_irq_mask);
+		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
+			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;
@@ -246,8 +247,9 @@
 
 	spin_lock(&mdss_lock);
 	if (!(mdss_res->irq_mask & ndx_bit)) {
-		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
-			hw->hw_ndx, mdss_res->mdp_irq_mask);
+		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
+			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;
@@ -359,6 +361,29 @@
 
 	return ret;
 }
+int mdss_mdp_hist_irq_enable(u32 irq)
+{
+	unsigned long irq_flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (mdss_res->mdp_hist_irq_mask & irq) {
+		pr_warn("MDSS MDP Hist IRQ-0x%x is already set, mask=%x\n",
+				irq, mdss_res->mdp_hist_irq_mask);
+		ret = -EBUSY;
+	} else {
+		pr_debug("MDP IRQ mask old=%x new=%x\n",
+				mdss_res->mdp_hist_irq_mask, irq);
+		mdss_res->mdp_hist_irq_mask |= irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, irq);
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_EN,
+				mdss_res->mdp_hist_irq_mask);
+		mdss_enable_irq(&mdss_mdp_hw);
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+
+	return ret;
+}
 
 void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
 {
@@ -376,7 +401,27 @@
 
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
 				mdss_res->mdp_irq_mask);
-		if (mdss_res->mdp_irq_mask == 0)
+		if ((mdss_res->mdp_irq_mask == 0) &&
+			(mdss_res->mdp_hist_irq_mask == 0))
+			mdss_disable_irq(&mdss_mdp_hw);
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdss_mdp_hist_irq_disable(u32 irq)
+{
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (!(mdss_res->mdp_hist_irq_mask & irq)) {
+		pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+				irq, mdss_res->mdp_hist_irq_mask);
+	} else {
+		mdss_res->mdp_hist_irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_EN,
+				mdss_res->mdp_hist_irq_mask);
+		if ((mdss_res->mdp_irq_mask == 0) &&
+			(mdss_res->mdp_hist_irq_mask == 0))
 			mdss_disable_irq(&mdss_mdp_hw);
 	}
 	spin_unlock_irqrestore(&mdp_lock, irq_flags);
@@ -396,7 +441,8 @@
 		mdss_res->mdp_irq_mask &= ~irq;
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
 				mdss_res->mdp_irq_mask);
-		if (mdss_res->mdp_irq_mask == 0)
+		if ((mdss_res->mdp_irq_mask == 0) &&
+			(mdss_res->mdp_hist_irq_mask == 0))
 			mdss_disable_irq_nosync(&mdss_mdp_hw);
 	}
 	spin_unlock(&mdp_lock);
@@ -1035,8 +1081,10 @@
 
 static const struct of_device_id mdss_mdp_dt_match[] = {
 	{ .compatible = "qcom,mdss_mdp",},
+	{}
 };
 MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
+EXPORT_COMPAT("qcom,mdss_mdp");
 
 static struct platform_driver mdss_mdp_driver = {
 	.probe = mdss_mdp_probe,
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index b03ef79..6fd642f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -29,7 +29,7 @@
 #define MDP_CLK_DEFAULT_RATE	37500000
 #define PHASE_STEP_SHIFT	21
 #define MAX_MIXER_WIDTH		2048
-#define MAX_MIXER_HEIGHT	2048
+#define MAX_MIXER_HEIGHT	2400
 #define MAX_IMG_WIDTH		0x3FFF
 #define MAX_IMG_HEIGHT		0x3FFF
 #define MIN_DST_W		10
@@ -251,6 +251,7 @@
 	void *priv_data;
 };
 
+#define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
 {
@@ -267,6 +268,8 @@
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
 void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
+int mdss_mdp_hist_irq_enable(u32 irq);
+void mdss_mdp_hist_irq_disable(u32 irq);
 void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
 int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
 			       void (*fnc_ptr)(void *), void *arg);
@@ -300,6 +303,20 @@
 				   struct mdp_csc_cfg *data);
 
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
+
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
+
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_collect(struct fb_info *info,
+		   struct mdp_histogram_data *hist, u32 *hist_data_addr);
+void mdss_mdp_hist_intr_done(u32 isr);
+
 
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index f72ff8d..5966989 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -351,6 +351,7 @@
 {
 	struct mdss_mdp_ctl *ctl;
 	u32 width, height;
+	int ret = 0;
 
 	if (!mfd)
 		return -ENODEV;
@@ -363,43 +364,54 @@
 		return -EINVAL;
 	}
 
-	ctl = mdss_mdp_ctl_alloc();
-
-	if (!ctl) {
-		pr_err("unable to allocate ctl\n");
-		return -ENOMEM;
+	if (!mfd->ctl) {
+		ctl = mdss_mdp_ctl_alloc();
+		if (!ctl) {
+			pr_err("unable to allocate ctl\n");
+			return -ENOMEM;
+		}
+		ctl->mfd = mfd;
+		mfd->ctl = ctl;
+	} else {
+		ctl = mfd->ctl;
 	}
 
-	ctl->mfd = mfd;
 	ctl->width = width;
 	ctl->height = height;
 	ctl->dst_format = mfd->panel_info.out_format;
 
-	ctl->mixer_left = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
 	if (!ctl->mixer_left) {
-		pr_err("unable to allocate layer mixer\n");
-		mdss_mdp_ctl_free(ctl);
-		return -ENOMEM;
+		ctl->mixer_left =
+			mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+		if (!ctl->mixer_left) {
+			pr_err("unable to allocate layer mixer\n");
+			ret = -ENOMEM;
+			goto ctl_init_fail;
+		}
 	}
 
-	ctl->mixer_left->width = MIN(width, MAX_MIXER_WIDTH);
+	if (width > MAX_MIXER_WIDTH)
+		width /= 2;
+
+	ctl->mixer_left->width = width;
 	ctl->mixer_left->height = height;
 	ctl->mixer_left->ctl = ctl;
 
-	width -= ctl->mixer_left->width;
-
-	if (width) {
-		ctl->mixer_right =
-		mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
-		if (!ctl->mixer_right) {
-			pr_err("unable to allocate layer mixer\n");
-			mdss_mdp_mixer_free(ctl->mixer_left);
-			mdss_mdp_ctl_free(ctl);
-			return -ENOMEM;
+	if (width < ctl->width) {
+		if (ctl->mixer_right == NULL) {
+			ctl->mixer_right =
+				mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+			if (!ctl->mixer_right) {
+				pr_err("unable to allocate right mixer\n");
+				ret = -ENOMEM;
+				goto ctl_init_fail;
+			}
 		}
 		ctl->mixer_right->width = width;
 		ctl->mixer_right->height = height;
 		ctl->mixer_right->ctl = ctl;
+	} else if (ctl->mixer_right) {
+		mdss_mdp_mixer_free(ctl->mixer_right);
 	}
 
 	switch (mfd->panel_info.type) {
@@ -431,9 +443,8 @@
 		break;
 	default:
 		pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
-		mdss_mdp_ctl_free(ctl);
-		return -EINVAL;
-
+		ret = -EINVAL;
+		goto ctl_init_fail;
 	}
 
 	ctl->opmode |= (ctl->intf_num << 4);
@@ -443,9 +454,17 @@
 			       MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT;
 	}
 
-	mfd->ctl = ctl;
+ctl_init_fail:
+	if (IS_ERR_VALUE(ret)) {
+		if (ctl->mixer_left)
+			mdss_mdp_mixer_free(ctl->mixer_left);
+		if (ctl->mixer_right)
+			mdss_mdp_mixer_free(ctl->mixer_right);
+		mdss_mdp_ctl_free(ctl);
+		mfd->ctl = NULL;
+	}
 
-	return 0;
+	return ret;
 }
 
 static int mdss_mdp_ctl_destroy(struct msm_fb_data_type *mfd)
@@ -486,12 +505,11 @@
 		return -ENODEV;
 	}
 
-	if (!mfd->ctl) {
-		if (mdss_mdp_ctl_init(mfd)) {
-			pr_err("unable to initialize ctl\n");
-			return -ENODEV;
-		}
+	if (mdss_mdp_ctl_init(mfd)) {
+		pr_err("unable to initialize ctl\n");
+		return -ENODEV;
 	}
+
 	ctl = mfd->ctl;
 
 	if (ctl->power_on) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 0139afd..651d595 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -74,6 +74,11 @@
 	MDSS_MDP_IRQ_INTF_VSYNC = 25,
 };
 
+#define MDSS_MDP_REG_IGC_VIG_BASE			0x300
+#define MDSS_MDP_REG_IGC_RGB_BASE			0x310
+#define MDSS_MDP_REG_IGC_DMA_BASE			0x320
+#define MDSS_MDP_REG_IGC_DSPP_BASE			0x400
+
 enum mdss_mdp_ctl_index {
 	MDSS_MDP_CTL0,
 	MDSS_MDP_CTL1,
@@ -189,6 +194,9 @@
 #define MDSS_MDP_REG_VIG_CSC_0_BASE			0x280
 #define MDSS_MDP_REG_VIG_CSC_1_BASE			0x320
 
+#define MDSS_MDP_REG_VIG_HIST_CTL_BASE			0x2C4
+#define MDSS_MDP_REG_VIG_HIST_LUT_BASE			0x2F0
+
 #define MDSS_MDP_SCALE_FILTER_NEAREST		0x0
 #define MDSS_MDP_SCALE_FILTER_BIL		0x1
 #define MDSS_MDP_SCALE_FILTER_PCMN		0x2
@@ -260,6 +268,8 @@
 #define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0	0x108
 #define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1	0x10C
 
+#define MDSS_MDP_REG_LM_GC_LUT_BASE	0x110
+
 #define MDSS_MDP_LM_BORDER_COLOR		(1 << 24)
 #define MDSS_MDP_LM_CURSOR_OUT			(1 << 25)
 #define MDSS_MDP_BLEND_FG_ALPHA_FG_CONST	(0 << 0)
@@ -323,7 +333,12 @@
 
 #define MDSS_MDP_REG_DSPP_OFFSET(pipe)	(0x4600 + ((pipe) * 0x400))
 #define MDSS_MDP_REG_DSPP_OP_MODE			0x000
+#define MDSS_MDP_REG_DSPP_PCC_BASE			0x030
+#define MDSS_MDP_REG_DSPP_DITHER_DEPTH			0x150
+#define MDSS_MDP_REG_DSPP_HIST_CTL_BASE			0x210
+#define MDSS_MDP_REG_DSPP_HIST_LUT_BASE			0x230
 #define MDSS_MDP_REG_DSPP_PA_BASE			0x238
+#define MDSS_MDP_REG_DSPP_GAMUT_BASE			0x2DC
 
 enum mdss_mpd_intf_index {
 	MDSS_MDP_NO_INTF,
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 91f94ea..f76b508 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -326,7 +326,6 @@
 	}
 
 	pipe->params_changed++;
-	pipe->play_cnt = 0;
 
 	req->id = pipe->ndx;
 
@@ -636,8 +635,15 @@
 	if (pipe == NULL) {
 		struct mdp_overlay req;
 		struct fb_info *fbi = mfd->fbi;
+		struct mdss_mdp_mixer *mixer;
 		int ret, bpp;
 
+		mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+		if (!mixer) {
+			pr_err("unable to retrieve mixer\n");
+			return -ENODEV;
+		}
+
 		memset(&req, 0, sizeof(req));
 
 		bpp = fbi->var.bits_per_pixel / 8;
@@ -646,20 +652,22 @@
 		req.src.height = fbi->var.yres;
 		req.src.width = fbi->fix.line_length / bpp;
 		if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
-			if (req.src.width <= MAX_MIXER_WIDTH)
-				return -ENODEV;
+			if (req.src.width <= mixer->width) {
+				pr_warn("right fb pipe not needed\n");
+				return -EINVAL;
+			}
 
 			req.flags |= MDSS_MDP_RIGHT_MIXER;
-			req.src_rect.x = MAX_MIXER_WIDTH;
-			req.src_rect.w = fbi->var.xres - MAX_MIXER_WIDTH;
+			req.src_rect.x = mixer->width;
+			req.src_rect.w = fbi->var.xres - mixer->width;
 		} else {
 			req.src_rect.x = 0;
-			req.src_rect.w = MIN(fbi->var.xres, MAX_MIXER_WIDTH);
+			req.src_rect.w = MIN(fbi->var.xres, mixer->width);
 		}
 
 		req.src_rect.y = 0;
 		req.src_rect.h = req.src.height;
-		req.dst_rect.x = req.src_rect.x;
+		req.dst_rect.x = 0;
 		req.dst_rect.y = 0;
 		req.dst_rect.w = req.src_rect.w;
 		req.dst_rect.h = req.src_rect.h;
@@ -695,7 +703,7 @@
 	fbi = mfd->fbi;
 
 	if (fbi->fix.smem_len == 0) {
-		pr_warn("fb memory not allocated\n");
+		mdss_mdp_overlay_kickoff(mfd->ctl);
 		return;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 331c0f9..6e04124 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -15,6 +15,9 @@
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
 
 struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
 	[MDSS_MDP_CSC_RGB2RGB] = {
@@ -74,25 +77,117 @@
 
 #define MDSS_BLOCK_DISP_NUM	(MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
 
+#define IGC_LUT_ENTRIES	256
+#define GC_LUT_SEGMENTS	16
+#define ENHIST_LUT_ENTRIES 256
+#define HIST_V_SIZE	256
+
+#define HIST_WAIT_TIMEOUT	1000
+/* hist collect state */
+enum {
+	HIST_UNKNOWN,
+	HIST_IDLE,
+	HIST_RESET,
+	HIST_START,
+	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;
+	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] = {
+	0, 0, 0, 0, 0, 1, 2, 3, 3};
+
+#define GAMUT_T0_SIZE	125
+#define GAMUT_T1_SIZE	100
+#define GAMUT_T2_SIZE	80
+#define GAMUT_T3_SIZE	100
+#define GAMUT_T4_SIZE	100
+#define GAMUT_T5_SIZE	80
+#define GAMUT_T6_SIZE	64
+#define GAMUT_T7_SIZE	80
+#define GAMUT_TOTAL_TABLE_SIZE (GAMUT_T0_SIZE + GAMUT_T1_SIZE + \
+	GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
+	GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
+
 struct pp_sts_type {
 	u32 pa_sts;
+	u32 pcc_sts;
+	u32 igc_sts;
+	u32 igc_tbl_idx;
+	u32 argc_sts;
+	u32 enhist_sts;
+	u32 dither_sts;
+	u32 gamut_sts;
 };
 
 #define PP_FLAGS_DIRTY_PA	0x1
+#define PP_FLAGS_DIRTY_PCC	0x2
+#define PP_FLAGS_DIRTY_IGC	0x4
+#define PP_FLAGS_DIRTY_ARGC	0x8
+#define PP_FLAGS_DIRTY_ENHIST	0x10
+#define PP_FLAGS_DIRTY_DITHER	0x20
+#define PP_FLAGS_DIRTY_GAMUT	0x40
+#define PP_FLAGS_DIRTY_HIST_COL	0x80
 
 #define PP_STS_ENABLE	0x1
+#define PP_STS_GAMUT_FIRST	0x2
 
 struct mdss_pp_res_type {
 	/* logical info */
 	u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM];
+	u32 igc_lut_c0c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+	u32 igc_lut_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+	struct mdp_ar_gc_lut_data
+		gc_lut_r[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+	struct mdp_ar_gc_lut_data
+		gc_lut_g[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+	struct mdp_ar_gc_lut_data
+		gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+	u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
 	struct mdp_pa_cfg_data pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pgc_lut_data pgc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_hist_lut_data enhist_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
+	struct pp_hist_col_info
+		*hist_col[MDSS_BLOCK_DISP_NUM][MDSS_MDP_MAX_DSPP];
+	u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
 	/* physical info */
 	struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP];
+	struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
 };
 
 static DEFINE_MUTEX(mdss_pp_mutex);
+static DEFINE_SPINLOCK(mdss_hist_lock);
+static DEFINE_MUTEX(mdss_mdp_hist_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
+
+static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info);
+
+static void pp_update_pcc_regs(u32 offset,
+				struct mdp_pcc_cfg_data *cfg_ptr);
+static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
+				u32 offset, u32 blk_idx);
+static void pp_update_gc_one_lut(u32 offset,
+		struct mdp_ar_gc_lut_data *lut_data);
+static void pp_update_argc_lut(u32 offset,
+		struct mdp_pgc_lut_data *config);
+
 int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
 				   struct mdp_csc_cfg *data)
 {
@@ -181,19 +276,123 @@
 	data = &mdp_csc_convert[csc_type];
 	return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
 }
-
-static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
 		struct mdss_mdp_mixer *mixer)
 {
-	u32 flags, base, offset, dspp_num, opmode = 0;
-	struct mdp_pa_cfg_data *pa_config;
+	u32 flags, offset, dspp_num, opmode = 0;
+	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
-
 	dspp_num = mixer->num;
 	/* no corresponding dspp */
 	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
 		(dspp_num >= MDSS_MDP_MAX_DSPP))
 		return 0;
+	if (disp_num < MDSS_BLOCK_DISP_NUM)
+		flags = mdss_pp_res->pp_disp_flags[disp_num];
+	else
+		flags = 0;
+
+	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+	/* GC_LUT is in layer mixer */
+	if (flags & PP_FLAGS_DIRTY_ARGC) {
+		pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
+		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+			offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
+				MDSS_MDP_REG_LM_GC_LUT_BASE;
+			pp_update_argc_lut(offset, pgc_config);
+		}
+		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->argc_sts &= ~PP_STS_ENABLE;
+		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->argc_sts |= PP_STS_ENABLE;
+		ctl->flush_bits |= BIT(6) << dspp_num; /* LAYER_MIXER */
+	}
+	/* update LM opmode if LM needs flush */
+	if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
+		(ctl->flush_bits & (BIT(6) << dspp_num))) {
+		offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+			MDSS_MDP_REG_LM_OP_MODE;
+		opmode = MDSS_MDP_REG_READ(offset);
+		opmode |= (1 << 0); /* GC_LUT_EN */
+		MDSS_MDP_REG_WRITE(offset, opmode);
+	}
+	return 0;
+}
+static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
+							u32 base,
+							u32 *gamut_sts)
+{
+	u32 offset;
+	int i, j;
+	if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
+		offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+				MDSS_MDP_REG_WRITE(offset,
+					(u32)gamut_cfg->r_tbl[i][j]);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+				MDSS_MDP_REG_WRITE(offset,
+					(u32)gamut_cfg->g_tbl[i][j]);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+				MDSS_MDP_REG_WRITE(offset,
+					(u32)gamut_cfg->b_tbl[i][j]);
+			offset += 4;
+		}
+		if (gamut_cfg->gamut_first)
+			*gamut_sts |= PP_STS_GAMUT_FIRST;
+	}
+
+	if (gamut_cfg->flags & MDP_PP_OPS_DISABLE)
+		*gamut_sts &= ~PP_STS_ENABLE;
+	else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
+		*gamut_sts |= PP_STS_ENABLE;
+}
+static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_mixer *mixer)
+{
+	u32 flags, base, offset, dspp_num, opmode = 0;
+	struct mdp_pa_cfg_data *pa_config;
+	struct mdp_pcc_cfg_data *pcc_config;
+	struct mdp_igc_lut_data *igc_config;
+	struct mdp_hist_lut_data *enhist_cfg;
+	struct mdp_dither_cfg_data *dither_cfg;
+	struct pp_hist_col_info *hist_info;
+	struct pp_sts_type *pp_sts;
+	u32 data, tbl_idx, col_state;
+	int i;
+	dspp_num = mixer->num;
+	/* no corresponding dspp */
+	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
+		(dspp_num >= MDSS_MDP_MAX_DSPP))
+		return 0;
+	base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
+	hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+	if (hist_info->col_en) {
+		/* HIST_EN & AUTO_CLEAR */
+		opmode |= (1 << 16) | (1 << 17);
+		mutex_lock(&mdss_mdp_hist_mutex);
+		if (hist_info->col_state == HIST_READY)
+			pp_hist_read(base + MDSS_MDP_REG_DSPP_HIST_CTL_BASE +
+				0x1C, hist_info);
+		spin_lock(&mdss_hist_lock);
+		col_state = hist_info->col_state;
+		if ((col_state == HIST_IDLE) ||
+			(col_state == HIST_READY) ||
+			(col_state == HIST_START)) {
+			/* Kick off collection */
+			MDSS_MDP_REG_WRITE(base +
+				MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
+			hist_info->col_state = HIST_START;
+		}
+		spin_unlock(&mdss_hist_lock);
+		mutex_unlock(&mdss_mdp_hist_mutex);
+	}
 
 	if (disp_num < MDSS_BLOCK_DISP_NUM)
 		flags = mdss_pp_res->pp_disp_flags[disp_num];
@@ -201,10 +400,9 @@
 		flags = 0;
 
 	/* nothing to update */
-	if (!flags)
+	if ((!flags) && (!(hist_info->col_en)))
 		return 0;
 	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
-	base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
 	if (flags & PP_FLAGS_DIRTY_PA) {
 		pa_config = &mdss_pp_res->pa_disp_cfg[disp_num];
 		if (pa_config->flags & MDP_PP_OPS_WRITE) {
@@ -224,10 +422,108 @@
 	}
 	if (pp_sts->pa_sts & PP_STS_ENABLE)
 		opmode |= (1 << 20); /* PA_EN */
+	if (flags & PP_FLAGS_DIRTY_PCC) {
+		pcc_config = &mdss_pp_res->pcc_disp_cfg[disp_num];
+		if (pcc_config->ops & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_PCC_BASE;
+			pp_update_pcc_regs(offset, pcc_config);
+		}
+		if (pcc_config->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
+		else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->pcc_sts & PP_STS_ENABLE)
+		opmode |= (1 << 4); /* PCC_EN */
+
+	if (flags & PP_FLAGS_DIRTY_IGC) {
+		igc_config = &mdss_pp_res->igc_disp_cfg[disp_num];
+		if (igc_config->ops & MDP_PP_OPS_WRITE) {
+			offset = MDSS_MDP_REG_IGC_DSPP_BASE;
+			pp_update_igc_lut(igc_config, offset, dspp_num);
+		}
+		if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+			tbl_idx = 1;
+		} else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
+			pp_sts->pcc_sts |= PP_STS_ENABLE;
+			tbl_idx = 2;
+		} else {
+			tbl_idx = 0;
+		}
+		pp_sts->igc_tbl_idx = tbl_idx;
+		if (igc_config->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->igc_sts &= ~PP_STS_ENABLE;
+		else if (igc_config->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->igc_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->igc_sts & PP_STS_ENABLE) {
+		opmode |= (1 << 0) | /* IGC_LUT_EN */
+			      (pp_sts->igc_tbl_idx << 1);
+	}
+	if (flags & PP_FLAGS_DIRTY_ENHIST) {
+		enhist_cfg = &mdss_pp_res->enhist_disp_cfg[disp_num];
+		if (enhist_cfg->ops & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+			for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+				MDSS_MDP_REG_WRITE(offset, enhist_cfg->data[i]);
+			/* swap */
+			MDSS_MDP_REG_WRITE(offset + 4, 1);
+		}
+		if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
+			pp_sts->enhist_sts &= ~PP_STS_ENABLE;
+		else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
+			pp_sts->enhist_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->enhist_sts & PP_STS_ENABLE) {
+		opmode |= (1 << 19) | /* HIST_LUT_EN */
+				  (1 << 20); /* PA_EN */
+		if (!(pp_sts->pa_sts & PP_STS_ENABLE)) {
+			/* Program default value */
+			offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
+			MDSS_MDP_REG_WRITE(offset, 0);
+			MDSS_MDP_REG_WRITE(offset + 4, 0);
+			MDSS_MDP_REG_WRITE(offset + 8, 0);
+			MDSS_MDP_REG_WRITE(offset + 12, 0);
+		}
+	}
+	if (flags & PP_FLAGS_DIRTY_DITHER) {
+		dither_cfg = &mdss_pp_res->dither_disp_cfg[disp_num];
+		if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
+			offset = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
+			MDSS_MDP_REG_WRITE(offset,
+			  dither_depth_map[dither_cfg->g_y_depth] |
+			  (dither_depth_map[dither_cfg->b_cb_depth] << 2) |
+			  (dither_depth_map[dither_cfg->r_cr_depth] << 4));
+			offset += 0x14;
+			for (i = 0; i << 16; i += 4) {
+				data = dither_matrix[i] |
+					(dither_matrix[i + 1] << 4) |
+					(dither_matrix[i + 2] << 8) |
+					(dither_matrix[i + 3] << 12);
+				MDSS_MDP_REG_WRITE(offset, data);
+				offset += 4;
+			}
+		}
+		if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
+			pp_sts->dither_sts &= ~PP_STS_ENABLE;
+		else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
+			pp_sts->dither_sts |= PP_STS_ENABLE;
+	}
+	if (pp_sts->dither_sts & PP_STS_ENABLE)
+		opmode |= (1 << 8); /* DITHER_EN */
+	if (flags & PP_FLAGS_DIRTY_GAMUT)
+		pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num],
+					base, &pp_sts->gamut_sts);
+	if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+		opmode |= (1 << 23); /* GAMUT_EN */
+		if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
+			opmode |= (1 << 24); /* GAMUT_ORDER */
+	}
+
 	MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
 	ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
 	return 0;
-
 }
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
 {
@@ -239,10 +535,14 @@
 	disp_num = ctl->mfd->index;
 
 	mutex_lock(&mdss_pp_mutex);
-	if (ctl->mixer_left)
+	if (ctl->mixer_left) {
+		pp_mixer_setup(disp_num, ctl, ctl->mixer_left);
 		pp_dspp_setup(disp_num, ctl, ctl->mixer_left);
-	if (ctl->mixer_right)
+	}
+	if (ctl->mixer_right) {
+		pp_mixer_setup(disp_num, ctl, ctl->mixer_right);
 		pp_dspp_setup(disp_num, ctl, ctl->mixer_right);
+	}
 	/* clear dirty flag */
 	if (disp_num < MDSS_BLOCK_DISP_NUM)
 		mdss_pp_res->pp_disp_flags[disp_num] = 0;
@@ -275,12 +575,31 @@
 		mutex_unlock(&mdss_pp_mutex);
 	}
 }
+static int pp_get_dspp_num(u32 disp_num, u32 *dspp_num)
+{
+	int i;
+	u32 mixer_cnt;
+	u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt)
+		return -EPERM;
+
+	/* only read the first mixer */
+	for (i = 0; i < mixer_cnt; i++) {
+		if (mixer_id[i] < MDSS_MDP_MAX_DSPP)
+			break;
+	}
+	if (i >= mixer_cnt)
+		return -EPERM;
+	*dspp_num = mixer_id[i];
+	return 0;
+}
 
 int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback)
 {
-	int i, ret = 0;
-	u32 pa_offset, disp_num, mixer_cnt;
-	u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	int ret = 0;
+	u32 pa_offset, disp_num, dspp_num = 0;
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
@@ -290,24 +609,15 @@
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
 	if (config->flags & MDP_PP_OPS_READ) {
-		mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
-		if (!mixer_cnt) {
-			ret = -EPERM;
-			goto pa_config_exit;
-		}
-		/* only read the first mixer */
-		for (i = 0; i < mixer_cnt; i++) {
-			if (mixer_id[i] < MDSS_MDP_MAX_DSPP)
-				break;
-		}
-		if (i >= mixer_cnt) {
-			ret = -EPERM;
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
 			goto pa_config_exit;
 		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		pa_offset = MDSS_MDP_REG_DSPP_OFFSET(mixer_id[i]) +
+		pa_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
 			  MDSS_MDP_REG_DSPP_PA_BASE;
-
 		config->hue_adj = MDSS_MDP_REG_READ(pa_offset);
 		pa_offset += 4;
 		config->sat_adj = MDSS_MDP_REG_READ(pa_offset);
@@ -326,3 +636,910 @@
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
+
+static void pp_read_pcc_regs(u32 offset,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	cfg_ptr->r.c = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.c = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.c = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.r = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.r = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.r = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.g = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.g = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.g = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.b = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.b = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.b = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rr = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rr = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rr = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rg = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rg = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rg = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rb = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rb = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rb = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.gg = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.gg = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.gg = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.gb = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.gb = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.gb = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.bb = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.bb = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.bb = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rgb_0 = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rgb_0 = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rgb_0 = MDSS_MDP_REG_READ(offset + 8);
+	offset += 0x10;
+
+	cfg_ptr->r.rgb_1 = MDSS_MDP_REG_READ(offset);
+	cfg_ptr->g.rgb_1 = MDSS_MDP_REG_READ(offset + 4);
+	cfg_ptr->b.rgb_1 = MDSS_MDP_REG_READ(offset + 8);
+}
+
+static void pp_update_pcc_regs(u32 offset,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.c);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.c);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.c);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.r);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.r);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.r);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.g);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.g);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.g);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.b);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.b);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.b);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rr);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rr);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rr);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rg);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rg);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rg);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rb);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rb);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rb);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gg);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gg);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gg);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gb);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gb);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gb);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.bb);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.bb);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.bb);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_0);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_0);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_0);
+	offset += 0x10;
+
+	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_1);
+	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_1);
+	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
+}
+
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, u32 *copyback)
+{
+	int ret = 0;
+	u32 base, disp_num, dspp_num = 0;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->ops & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto pcc_config_exit;
+		}
+
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_PCC_BASE;
+		pp_read_pcc_regs(base, config);
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		mdss_pp_res->pcc_disp_cfg[disp_num] = *config;
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PCC;
+	}
+
+pcc_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+
+}
+
+static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
+				u32 offset, u32 blk_idx)
+{
+	int i;
+	u32 data;
+
+	/* INDEX_UPDATE & VALUE_UPDATEN */
+	data = (3 << 24) | (((~(1 << blk_idx)) & 0x7) << 28);
+	MDSS_MDP_REG_WRITE(offset, data);
+
+	for (i = 0; i < cfg->len; i++)
+		cfg->c0_c1_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+
+	offset += 0x4;
+	MDSS_MDP_REG_WRITE(offset, data);
+	for (i = 0; i < cfg->len; i++)
+		cfg->c0_c1_data[i] |= (MDSS_MDP_REG_READ(offset) & 0xFFF) << 16;
+
+	offset += 0x4;
+	MDSS_MDP_REG_WRITE(offset, data);
+	for (i = 0; i < cfg->len; i++)
+		cfg->c2_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+}
+
+static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
+				u32 offset, u32 blk_idx)
+{
+	int i;
+	u32 data;
+	/* INDEX_UPDATE */
+	data = (1 << 25) | (((~(1 << blk_idx)) & 0x7) << 28);
+	MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[0] & 0xFFF) | data);
+
+	/* disable index update */
+	data &= ~(1 << 25);
+	for (i = 1; i < cfg->len; i++)
+		MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[i] & 0xFFF) | data);
+
+	offset += 0x4;
+	data |= (1 << 25);
+	MDSS_MDP_REG_WRITE(offset, ((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data);
+	data &= ~(1 << 25);
+	for (i = 1; i < cfg->len; i++)
+		MDSS_MDP_REG_WRITE(offset,
+		((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data);
+
+	offset += 0x4;
+	data |= (1 << 25);
+	MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[0] & 0xFFF) | data);
+	data &= ~(1 << 25);
+	for (i = 1; i < cfg->len; i++)
+		MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
+}
+
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback)
+{
+	int ret = 0;
+	u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
+	struct mdp_igc_lut_data local_cfg;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->ops & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto igc_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		if (config->ops & MDP_PP_IGC_FLAG_ROM0)
+			tbl_idx = 1;
+		else if (config->ops & MDP_PP_IGC_FLAG_ROM1)
+			tbl_idx = 2;
+		else
+			tbl_idx = 0;
+		igc_offset = MDSS_MDP_REG_IGC_DSPP_BASE + (0x10 * tbl_idx);
+		local_cfg = *config;
+		local_cfg.c0_c1_data =
+			&mdss_pp_res->igc_lut_c0c1[disp_num][0];
+		local_cfg.c2_data =
+			&mdss_pp_res->igc_lut_c2[disp_num][0];
+		pp_read_igc_lut(&local_cfg, igc_offset, dspp_num);
+		if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
+			config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		if (copy_to_user(config->c2_data, local_cfg.c0_c1_data,
+			config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (copy_from_user(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+			config->c0_c1_data, config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		if (copy_from_user(&mdss_pp_res->igc_lut_c2[disp_num][0],
+			config->c2_data, config->len * sizeof(u32))) {
+			ret = -EFAULT;
+			goto igc_config_exit;
+		}
+		mdss_pp_res->igc_disp_cfg[disp_num] = *config;
+		mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
+			&mdss_pp_res->igc_lut_c0c1[disp_num][0];
+		mdss_pp_res->igc_disp_cfg[disp_num].c2_data =
+			&mdss_pp_res->igc_lut_c2[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_IGC;
+	}
+
+igc_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+static void pp_update_gc_one_lut(u32 offset,
+		struct mdp_ar_gc_lut_data *lut_data)
+{
+	int i, start_idx;
+
+	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+	for (i = 0; i < start_idx; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+	offset += 4;
+	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+	for (i = 0; i < start_idx; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+	offset += 4;
+	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+	for (i = 0; i < start_idx; i++)
+		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+}
+static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
+{
+	pp_update_gc_one_lut(offset, config->r_data);
+	offset += 0x10;
+	pp_update_gc_one_lut(offset, config->g_data);
+	offset += 0x10;
+	pp_update_gc_one_lut(offset, config->b_data);
+}
+static void pp_read_gc_one_lut(u32 offset,
+		struct mdp_ar_gc_lut_data *gc_data)
+{
+	int i, start_idx, data;
+	data = MDSS_MDP_REG_READ(offset);
+	start_idx = (data >> 16) & 0xF;
+	gc_data[start_idx].x_start = data & 0xFFF;
+
+	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].x_start = data & 0xFFF;
+	}
+	for (i = 0; i < start_idx; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].x_start = data & 0xFFF;
+	}
+
+	offset += 4;
+	data = MDSS_MDP_REG_READ(offset);
+	start_idx = (data >> 16) & 0xF;
+	gc_data[start_idx].slope = data & 0x7FFF;
+	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].slope = data & 0x7FFF;
+	}
+	for (i = 0; i < start_idx; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].slope = data & 0x7FFF;
+	}
+	offset += 4;
+	data = MDSS_MDP_REG_READ(offset);
+	start_idx = (data >> 16) & 0xF;
+	gc_data[start_idx].offset = data & 0x7FFF;
+	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].offset = data & 0x7FFF;
+	}
+	for (i = 0; i < start_idx; i++) {
+		data = MDSS_MDP_REG_READ(offset);
+		gc_data[i].offset = data & 0x7FFF;
+	}
+}
+
+static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, u32 offset)
+{
+	int ret = 0;
+	pp_read_gc_one_lut(offset, config->r_data);
+	offset += 0x10;
+	pp_read_gc_one_lut(offset, config->g_data);
+	offset += 0x10;
+	pp_read_gc_one_lut(offset, config->b_data);
+	return ret;
+}
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
+{
+	int ret = 0;
+	u32 argc_offset, disp_num, dspp_num = 0;
+	struct mdp_pgc_lut_data local_cfg;
+	u32 tbl_size;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	tbl_size = GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
+	if (config->flags & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto argc_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+				MDSS_MDP_REG_LM_GC_LUT_BASE;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		local_cfg = *config;
+		local_cfg.r_data =
+			&mdss_pp_res->gc_lut_r[disp_num][0];
+		local_cfg.g_data =
+			&mdss_pp_res->gc_lut_g[disp_num][0];
+		local_cfg.b_data =
+			&mdss_pp_res->gc_lut_b[disp_num][0];
+		pp_read_argc_lut(&local_cfg, argc_offset);
+		if (copy_to_user(config->r_data,
+			&mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_to_user(config->g_data,
+			&mdss_pp_res->gc_lut_g[disp_num][0], tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_to_user(config->b_data,
+			&mdss_pp_res->gc_lut_b[disp_num][0], tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (copy_from_user(&mdss_pp_res->gc_lut_r[disp_num][0],
+			config->r_data, tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_from_user(&mdss_pp_res->gc_lut_g[disp_num][0],
+			config->g_data, tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		if (copy_from_user(&mdss_pp_res->gc_lut_b[disp_num][0],
+			config->b_data, tbl_size)) {
+			ret = -EFAULT;
+			goto argc_config_exit;
+		}
+		mdss_pp_res->pgc_disp_cfg[disp_num] = *config;
+		mdss_pp_res->pgc_disp_cfg[disp_num].r_data =
+			&mdss_pp_res->gc_lut_r[disp_num][0];
+		mdss_pp_res->pgc_disp_cfg[disp_num].g_data =
+			&mdss_pp_res->gc_lut_g[disp_num][0];
+		mdss_pp_res->pgc_disp_cfg[disp_num].b_data =
+			&mdss_pp_res->gc_lut_b[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ARGC;
+	}
+argc_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback)
+{
+	int i, ret = 0;
+	u32 hist_offset, disp_num, dspp_num = 0;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->ops & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto enhist_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		hist_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+		for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+			mdss_pp_res->enhist_lut[disp_num][i] =
+				MDSS_MDP_REG_READ(hist_offset);
+		if (copy_to_user(config->data,
+			&mdss_pp_res->enhist_lut[disp_num][0],
+			ENHIST_LUT_ENTRIES * sizeof(u32))) {
+			ret = -EFAULT;
+			goto enhist_config_exit;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (copy_from_user(&mdss_pp_res->enhist_lut[disp_num][0],
+			config->data, ENHIST_LUT_ENTRIES * sizeof(u32))) {
+			ret = -EFAULT;
+			goto enhist_config_exit;
+		}
+		mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
+		mdss_pp_res->enhist_disp_cfg[disp_num].data =
+			&mdss_pp_res->enhist_lut[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ENHIST;
+	}
+enhist_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+{
+	u32 disp_num;
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+	if (config->flags & MDP_PP_OPS_READ)
+		return -ENOTSUPP;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+	mdss_pp_res->dither_disp_cfg[disp_num] = *config;
+	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
+	mutex_unlock(&mdss_pp_mutex);
+	return 0;
+}
+
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback)
+{
+	int i, j, size_total = 0, ret = 0;
+	u32 offset, disp_num, dspp_num = 0;
+	uint16_t *tbl_off;
+	struct mdp_gamut_cfg_data local_cfg;
+
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+	for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++)
+		size_total += config->tbl_size[i];
+	if (size_total != GAMUT_TOTAL_TABLE_SIZE)
+		return -EINVAL;
+
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+	if (config->flags & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("%s, no dspp connects to disp %d",
+				__func__, disp_num);
+			goto gamut_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_GAMUT_BASE;
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < config->tbl_size[i]; j++)
+				config->r_tbl[i][j] =
+					(u16)MDSS_MDP_REG_READ(offset);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < config->tbl_size[i]; j++)
+				config->g_tbl[i][j] =
+					(u16)MDSS_MDP_REG_READ(offset);
+			offset += 4;
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			for (j = 0; j < config->tbl_size[i]; j++)
+				config->b_tbl[i][j] =
+					(u16)MDSS_MDP_REG_READ(offset);
+			offset += 4;
+		}
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		local_cfg = *config;
+		tbl_off = mdss_pp_res->gamut_tbl[disp_num];
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			local_cfg.r_tbl[i] = tbl_off;
+			if (copy_from_user(tbl_off, config->r_tbl[i],
+				config->tbl_size[i] * sizeof(uint16_t))) {
+				ret = -EFAULT;
+				goto gamut_config_exit;
+			}
+			tbl_off += local_cfg.tbl_size[i];
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			local_cfg.g_tbl[i] = tbl_off;
+			if (copy_from_user(tbl_off, config->g_tbl[i],
+				config->tbl_size[i] * sizeof(uint16_t))) {
+				ret = -EFAULT;
+				goto gamut_config_exit;
+			}
+			tbl_off += local_cfg.tbl_size[i];
+		}
+		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			local_cfg.b_tbl[i] = tbl_off;
+			if (copy_from_user(tbl_off, config->b_tbl[i],
+				config->tbl_size[i] * sizeof(uint16_t))) {
+				ret = -EFAULT;
+				goto gamut_config_exit;
+			}
+			tbl_off += local_cfg.tbl_size[i];
+		}
+		mdss_pp_res->gamut_disp_cfg[disp_num] = local_cfg;
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_GAMUT;
+	}
+gamut_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
+}
+static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
+{
+	int i, i_start;
+	u32 data;
+	data = MDSS_MDP_REG_READ(v_base);
+	i_start = data >> 24;
+	hist_info->data[i_start] = data & 0xFFFFFF;
+	for (i = i_start + 1; i < HIST_V_SIZE; i++)
+		hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+	for (i = 0; i < i_start - 1; i++)
+		hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+	hist_info->hist_cnt_read++;
+}
+
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+{
+	u32 ctl_base, done_shift_bit;
+	struct pp_hist_col_info *hist_info;
+	int i, ret = 0;
+	u32 disp_num, dspp_num = 0;
+	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+	if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(req->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_hist_mutex);
+	disp_num = req->block - MDP_LOGICAL_BLOCK_DISP_0;
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt) {
+		pr_err("%s, no dspp connects to disp %d",
+			__func__, disp_num);
+		ret = -EPERM;
+		goto hist_start_exit;
+	}
+	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+		pr_err("%s, Too many dspp connects to disp %d",
+			__func__, mixer_cnt);
+		ret = -EPERM;
+		goto hist_start_exit;
+	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	for (i = 0; i < mixer_cnt; i++) {
+		dspp_num = mixer_id[i];
+		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+		done_shift_bit = (dspp_num * 4) + 12;
+		/* check if it is idle */
+		if (hist_info->col_en) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+			pr_info("%s Hist collection has already been enabled %d",
+				__func__, dspp_num);
+			goto hist_start_exit;
+		}
+		spin_lock(&mdss_hist_lock);
+		hist_info->frame_cnt = req->frame_cnt;
+		init_completion(&hist_info->comp);
+		hist_info->hist_cnt_read = 0;
+		hist_info->hist_cnt_sent = 0;
+		hist_info->read_request = false;
+		hist_info->col_state = HIST_RESET;
+		hist_info->col_en = true;
+		spin_unlock(&mdss_hist_lock);
+		mdss_pp_res->hist_col[disp_num][i] =
+			&mdss_pp_res->dspp_hist[dspp_num];
+		mdss_mdp_hist_irq_enable(3 << done_shift_bit);
+		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+		MDSS_MDP_REG_WRITE(ctl_base + 8, req->frame_cnt);
+		/* Kick out reset start */
+		MDSS_MDP_REG_WRITE(ctl_base + 4, 1);
+	}
+	for (i = mixer_cnt; i < MDSS_MDP_MAX_DSPP; i++)
+		mdss_pp_res->hist_col[disp_num][i] = 0;
+	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_start_exit:
+	mutex_unlock(&mdss_mdp_hist_mutex);
+	return ret;
+}
+
+int mdss_mdp_histogram_stop(u32 block)
+{
+	int i, ret = 0;
+	u32 dspp_num, disp_num, ctl_base, done_bit;
+	struct pp_hist_col_info *hist_info;
+	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+	if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_hist_mutex);
+	disp_num = block - MDP_LOGICAL_BLOCK_DISP_0;
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt) {
+		pr_err("%s, no dspp connects to disp %d",
+			__func__, disp_num);
+		ret = -EPERM;
+		goto hist_stop_exit;
+	}
+	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+		pr_err("%s, Too many dspp connects to disp %d",
+			__func__, mixer_cnt);
+		ret = -EPERM;
+		goto hist_stop_exit;
+	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	for (i = 0; i < mixer_cnt; i++) {
+		dspp_num = mixer_id[i];
+		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+		done_bit = 3 << ((dspp_num * 4) + 12);
+		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+		if (hist_info->col_en == false) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+			goto hist_stop_exit;
+		}
+		complete_all(&hist_info->comp);
+		spin_lock(&mdss_hist_lock);
+		hist_info->col_en = false;
+		hist_info->col_state = HIST_UNKNOWN;
+		spin_unlock(&mdss_hist_lock);
+		mdss_mdp_hist_irq_disable(done_bit);
+		MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
+	}
+	for (i = 0; i < MDSS_MDP_MAX_DSPP; i++)
+		mdss_pp_res->hist_col[disp_num][i] = 0;
+	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_stop_exit:
+	mutex_unlock(&mdss_mdp_hist_mutex);
+	return ret;
+}
+
+int mdss_mdp_hist_collect(struct fb_info *info,
+		  struct mdp_histogram_data *hist, u32 *hist_data_addr)
+{
+	int i, j, wait_ret, ret = 0;
+	u32 timeout, v_base;
+	struct pp_hist_col_info *hist_info;
+	u32 dspp_num, disp_num, ctl_base;
+	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+	if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(hist->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_hist_mutex);
+	disp_num = hist->block - MDP_LOGICAL_BLOCK_DISP_0;
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+	if (!mixer_cnt) {
+		pr_err("%s, no dspp connects to disp %d",
+			__func__, disp_num);
+		ret = -EPERM;
+		goto hist_collect_exit;
+	}
+	if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+		pr_err("%s, Too many dspp connects to disp %d",
+			__func__, mixer_cnt);
+		ret = -EPERM;
+		goto hist_collect_exit;
+	}
+	hist_info = &mdss_pp_res->dspp_hist[0];
+	for (i = 0; i < mixer_cnt; i++) {
+		dspp_num = mixer_id[i];
+		hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+		ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+			  MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+		if ((hist_info->col_en == 0) ||
+			(hist_info->col_state == HIST_UNKNOWN)) {
+			ret = -EINVAL;
+			goto hist_collect_exit;
+		}
+		spin_lock(&mdss_hist_lock);
+		if ((hist_info->col_state == HIST_READY) ||
+			(hist_info->hist_cnt_read == 0)) {
+			/* wait for hist done if cache has no data */
+			if ((hist_info->col_state != HIST_READY) &&
+				(hist_info->hist_cnt_read == 0)) {
+				hist_info->read_request = true;
+				spin_unlock(&mdss_hist_lock);
+				timeout = HIST_WAIT_TIMEOUT *
+					hist_info->frame_cnt;
+				mutex_unlock(&mdss_mdp_hist_mutex);
+				wait_ret = wait_for_completion_killable_timeout(
+					&(hist_info->comp), timeout);
+
+				mutex_lock(&mdss_mdp_hist_mutex);
+				hist_info->read_request = false;
+				if (wait_ret == 0) {
+					ret = -ETIMEDOUT;
+					pr_debug("%s: bin collection timedout",
+						__func__);
+					goto hist_collect_exit;
+				} else if (wait_ret < 0) {
+					ret = -EINTR;
+					pr_debug("%s: bin collection interrupted",
+						__func__);
+					goto hist_collect_exit;
+				}
+				if (hist_info->col_state != HIST_READY) {
+					ret = -EBUSY;
+					pr_err("%s: collection state is not ready: %d",
+						__func__, hist_info->col_state);
+					goto hist_collect_exit;
+				}
+			} else {
+				spin_unlock(&mdss_hist_lock);
+			}
+			if (hist_info->col_state == HIST_READY) {
+				v_base = ctl_base + 0x1C;
+				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+				pp_hist_read(v_base, hist_info);
+				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+				spin_lock(&mdss_hist_lock);
+				hist_info->col_state = HIST_IDLE;
+				spin_unlock(&mdss_hist_lock);
+			}
+		} else {
+			spin_unlock(&mdss_hist_lock);
+		}
+		hist_info->hist_cnt_sent = hist_info->hist_cnt_read;
+	}
+	if (mixer_cnt > 1) {
+		memset(&mdss_pp_res->hist_data[disp_num][0],
+			0, HIST_V_SIZE * sizeof(u32));
+		for (i = 0; i < mixer_cnt; i++) {
+			dspp_num = mixer_id[i];
+			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+			for (j = 0; j < HIST_V_SIZE; j++)
+				mdss_pp_res->hist_data[disp_num][i] +=
+					hist_info->data[i];
+		}
+		*hist_data_addr = (u32)&mdss_pp_res->hist_data[disp_num][0];
+	} else {
+		*hist_data_addr = (u32)hist_info->data;
+	}
+
+hist_collect_exit:
+	mutex_unlock(&mdss_mdp_hist_mutex);
+	return ret;
+}
+void mdss_mdp_hist_intr_done(u32 isr)
+{
+	u32 isr_blk, blk_idx;
+	struct pp_hist_col_info *hist_info;
+	isr &= 0x333333;
+	while (isr != 0) {
+		if (isr & 0xFFF000) {
+			if (isr & 0x3000) {
+				blk_idx = 0;
+				isr_blk = (isr >> 12) & 0x3;
+				isr &= ~0x3000;
+			} else if (isr & 0x30000) {
+				blk_idx = 1;
+				isr_blk = (isr >> 16) & 0x3;
+				isr &= ~0x30000;
+			} else {
+				blk_idx = 2;
+				isr_blk = (isr >> 20) & 0x3;
+				isr &= ~0x300000;
+			}
+			hist_info = &mdss_pp_res->dspp_hist[blk_idx];
+		} else {
+			if (isr & 0x3) {
+				blk_idx = 0;
+				isr_blk = isr & 0x3;
+				isr &= ~0x3;
+			} else if (isr & 0x30) {
+				blk_idx = 1;
+				isr_blk = (isr >> 4) & 0x3;
+				isr &= ~0x30;
+			} else {
+				blk_idx = 2;
+				isr_blk = (isr >> 8) & 0x3;
+				isr &= ~0x300;
+			}
+			/* SSPP block, not support yet*/
+			continue;
+		}
+		/* Histogram Done Interrupt */
+		if ((isr_blk & 0x1) &&
+			(hist_info->col_en)) {
+			spin_lock(&mdss_hist_lock);
+			hist_info->col_state = HIST_READY;
+			spin_unlock(&mdss_hist_lock);
+			if (hist_info->read_request)
+				complete(&hist_info->comp);
+		}
+		/* Histogram Reset Done Interrupt */
+		if ((isr_blk & 0x2) &&
+			(hist_info->col_en)) {
+				spin_lock(&mdss_hist_lock);
+				hist_info->col_state = HIST_IDLE;
+				spin_unlock(&mdss_hist_lock);
+		}
+	};
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 57e8441..95c92fc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -112,22 +112,22 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr)
 {
-	u32 isr, mask;
+	u32 isr, mask, hist_isr, hist_mask;
 
 
 	isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
 
-	pr_debug("isr=%x\n", isr);
-
 	if (isr == 0)
-		goto done;
+		goto mdp_isr_done;
+
+	pr_debug("isr=%x\n", isr);
 
 	mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
 	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
 
 	isr &= mask;
 	if (isr == 0)
-		goto done;
+		goto mdp_isr_done;
 
 	if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
 		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
@@ -159,7 +159,17 @@
 	if (isr & MDSS_MDP_INTR_WB_2_DONE)
 		mdss_mdp_intr_done(MDP_INTR_WB_2);
 
-done:
+mdp_isr_done:
+	hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
+	if (hist_isr == 0)
+		goto hist_isr_done;
+	hist_mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_EN);
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, hist_isr);
+	hist_isr &= hist_mask;
+	if (hist_isr == 0)
+		goto hist_isr_done;
+	mdss_mdp_hist_intr_done(hist_isr);
+hist_isr_done:
 	return IRQ_HANDLED;
 }
 
@@ -203,7 +213,7 @@
 	} else {
 		u8 hmap[] = { 1, 2, 1, 2 };
 		u8 vmap[] = { 1, 1, 2, 2 };
-		u8 horiz, vert, stride_align;
+		u8 horiz, vert, stride_align, height_align;
 
 		horiz = hmap[fmt->chroma_sample];
 		vert = vmap[fmt->chroma_sample];
@@ -211,18 +221,21 @@
 		switch (format) {
 		case MDP_Y_CR_CB_GH2V2:
 			stride_align = 16;
+			height_align = 1;
 			break;
 		case MDP_Y_CBCR_H2V2_VENUS:
 			stride_align = 32;
+			height_align = 32;
 			break;
 		default:
 			stride_align = 1;
+			height_align = 1;
 			break;
 		}
 
 		ps->ystride[0] = ALIGN(w, stride_align);
 		ps->ystride[1] = ALIGN(w / horiz, stride_align);
-		ps->plane_size[0] = ps->ystride[0] * h;
+		ps->plane_size[0] = ps->ystride[0] * ALIGN(h, height_align);
 		ps->plane_size[1] = ps->ystride[1] * (h / vert);
 
 		if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 2b75193..60311dc 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -25,6 +25,7 @@
 #include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/iopoll.h>
 
 #include <asm/system.h>
 #include <asm/mach-types.h>
@@ -964,31 +965,30 @@
 
 	uint32 dsi_ctrl;
 	uint32 status;
-	int cnt;
+	u32 sleep_us = 1000;
+	u32 timeout_us = 16000;
 
-	cnt = 16;
-	while (cnt--) {
-		status = MIPI_INP(MIPI_DSI_BASE + 0x0004);
-		status &= 0x02;		/* CMD_MODE_DMA_BUSY */
-		if (status == 0)
-			break;
-		usleep(1000);
-	}
-	if (cnt == 0)
+	/* Check for CMD_MODE_DMA_BUSY */
+	if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004),
+			   status,
+			   ((status & 0x02) == 0),
+			       sleep_us, timeout_us))
 		pr_info("%s: DSI status=%x failed\n", __func__, status);
 
-	cnt = 16;
-	while (cnt--) {
-		status = MIPI_INP(MIPI_DSI_BASE + 0x0008);
-		status &= 0x11111000;	/* x_HS_FIFO_EMPTY */
-		if (status == 0x11111000)	/* all empty */
-			break;
-		usleep(1000);
-	}
-
-	if (cnt == 0)
+	/* Check for x_HS_FIFO_EMPTY */
+	if (readl_poll_timeout((MIPI_DSI_BASE + 0x0008),
+			   status,
+			   ((status & 0x11111000) == 0x11111000),
+			       sleep_us, timeout_us))
 		pr_info("%s: FIFO status=%x failed\n", __func__, status);
 
+	/* Check for VIDEO_MODE_ENGINE_BUSY */
+	if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004),
+			   status,
+			   ((status & 0x08) == 0),
+			       sleep_us, timeout_us))
+		pr_info("%s: DSI status=%x failed\n", __func__, status);
+
 	dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000);
 	if (enable)
 		dsi_ctrl |= 0x01;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 9c55fe8..1994b1b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -185,8 +185,9 @@
 
 	if (!bl_lvl && value)
 		bl_lvl = 1;
-
+	down(&mfd->sem);
 	msm_fb_set_backlight(mfd, bl_lvl);
+	up(&mfd->sem);
 }
 
 static struct led_classdev backlight_led = {
@@ -809,7 +810,9 @@
 						struct mdp_bl_scale_data *data)
 {
 	int ret = 0;
-	int curr_bl = mfd->bl_level;
+	int curr_bl;
+	down(&mfd->sem);
+	curr_bl = mfd->bl_level;
 	bl_scale = data->scale;
 	bl_min_lvl = data->min_lvl;
 	pr_debug("%s: update scale = %d, min_lvl = %d\n", __func__, bl_scale,
@@ -817,6 +820,7 @@
 
 	/* update current backlight to use new scaling*/
 	msm_fb_set_backlight(mfd, curr_bl);
+	up(&mfd->sem);
 
 	return ret;
 }
@@ -824,6 +828,7 @@
 static void msm_fb_scale_bl(__u32 *bl_lvl)
 {
 	__u32 temp = *bl_lvl;
+	pr_debug("%s: input = %d, scale = %d", __func__, temp, bl_scale);
 	if (temp >= bl_min_lvl) {
 		/* bl_scale is the numerator of scaling fraction (x/1024)*/
 		temp = ((*bl_lvl) * bl_scale) / 1024;
@@ -832,10 +837,12 @@
 		if (temp < bl_min_lvl)
 			temp = bl_min_lvl;
 	}
+	pr_debug("%s: output = %d", __func__, temp);
 
 	(*bl_lvl) = temp;
 }
 
+/*must call this function from within mfd->sem*/
 void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
 {
 	struct msm_fb_panel_data *pdata;
@@ -847,20 +854,17 @@
 		unset_bl_level = 0;
 	}
 
-	msm_fb_scale_bl(&temp);
 	pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
 
 	if ((pdata) && (pdata->set_backlight)) {
-		down(&mfd->sem);
+		msm_fb_scale_bl(&temp);
 		if (bl_level_old == temp) {
-			up(&mfd->sem);
 			return;
 		}
 		mfd->bl_level = temp;
 		pdata->set_backlight(mfd);
 		mfd->bl_level = bkl_lvl;
 		bl_level_old = temp;
-		up(&mfd->sem);
 	}
 }
 
@@ -2957,6 +2961,19 @@
 	return ret;
 }
 
+static int msmfb_overlay_commit(struct fb_info *info, unsigned long *argp)
+{
+	int ret, ndx;
+
+	ret = copy_from_user(&ndx, argp, sizeof(ndx));
+	if (ret) {
+		pr_err("%s: ioctl failed\n", __func__);
+		return ret;
+	}
+
+	return mdp4_overlay_commit(info, ndx);
+}
+
 static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
 {
 	int	ret;
@@ -3376,49 +3393,36 @@
 	switch (cmd) {
 #ifdef CONFIG_FB_MSM_OVERLAY
 	case MSMFB_OVERLAY_GET:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_get(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_SET:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_set(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_UNSET:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_unset(info, argp);
+		break;
+	case MSMFB_OVERLAY_COMMIT:
+		down(&msm_fb_ioctl_ppp_sem);
+		ret = msmfb_overlay_commit(info, argp);
 		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_PLAY:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_play(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_PLAY_ENABLE:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_play_enable(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_PLAY_WAIT:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_play_wait(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_BLT:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_blt(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_OVERLAY_3D:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_3d_sbys(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_MIXER_INFO:
-		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_mixer_info(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
 		break;
 	case MSMFB_WRITEBACK_INIT:
 		ret = msmfb_overlay_ioctl_writeback_init(info);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 2896349..7dc89ef 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -37,7 +37,6 @@
 #include <linux/fb.h>
 #include <linux/list.h>
 #include <linux/types.h>
-
 #include <linux/msm_mdp.h>
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
@@ -189,6 +188,7 @@
 	int cont_splash_done;
 	void *copy_splash_buf;
 	unsigned char *copy_splash_phys;
+	void *cpu_pm_hdl;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/msm_fb_bl.c b/drivers/video/msm/msm_fb_bl.c
index 9afbbf1..b21adee 100644
--- a/drivers/video/msm/msm_fb_bl.c
+++ b/drivers/video/msm/msm_fb_bl.c
@@ -34,7 +34,9 @@
 
 	bl_lvl = pbd->props.brightness;
 	bl_lvl = mfd->fbi->bl_curve[bl_lvl];
+	down(&mfd->sem);
 	msm_fb_set_backlight(mfd, bl_lvl);
+	up(&mfd->sem);
 	return 0;
 }
 
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index a2c3db1..7fc7a2f 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -168,7 +168,7 @@
 	__u32 frame_count;
 	__u32 is_3d_panel;
 	__u32 frame_rate;
-
+	__u32 frame_interval;
 
 	struct mddi_panel_info mddi;
 	struct lcd_panel_info lcd;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 400a3a7..2a850d8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -292,6 +292,7 @@
 	u32  num_slices_comp;
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
+	u32 avc_delimiter_enable;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 931c1c8..d6558c3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1047,6 +1047,20 @@
 	case VCD_REQ_PERF_LEVEL:
 		vcd_status = VCD_S_SUCCESS;
 		break;
+	case VCD_I_ENABLE_DELIMITER_FLAG:
+	{
+		struct vcd_property_avc_delimiter_enable *delimiter_enable =
+			(struct vcd_property_avc_delimiter_enable *)
+				property_value;
+		if (sizeof(struct vcd_property_avc_delimiter_enable) ==
+			property_hdr->sz &&
+			encoder->codec.codec == VCD_CODEC_H264) {
+			encoder->avc_delimiter_enable =
+			delimiter_enable->avc_delimiter_enable_flag;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
 	default:
 		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1530,6 +1544,15 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 		break;
+	case VCD_I_ENABLE_DELIMITER_FLAG:
+		if (sizeof(struct vcd_property_avc_delimiter_enable) ==
+			property_hdr->sz) {
+			((struct vcd_property_avc_delimiter_enable *)
+				property_value)->avc_delimiter_enable_flag =
+					encoder->avc_delimiter_enable;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1691,6 +1714,7 @@
 	encoder->slice_delivery_info.enable = 0;
 	encoder->slice_delivery_info.num_slices = 0;
 	encoder->slice_delivery_info.num_slices_enc = 0;
+	encoder->avc_delimiter_enable = 0;
 }
 
 static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 8099234..40dc2aa 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_ADDR                    0x0028
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK    0xffff0000
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT    16
+#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK    0x00000800
+#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT    11
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT  7
 #define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK    0X100
@@ -446,10 +448,10 @@
 	*shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip frame_skip_mode,
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
-	u32 sps_pps_control, u32 closed_gop_enable)
+	u32 sps_pps_control, u32 closed_gop_enable,
+	u32 au_delim_enable)
 {
 	u32 enc_ctrl;
-
 	enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_SHFT,
 			VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_BMSK) |
@@ -470,7 +472,11 @@
 			VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK) |
 			VIDC_SETFIELD(closed_gop_enable,
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
-			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
+			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
+			VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 9cb1933..c4d577b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
 	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
-	u32 closed_gop_enable);
+	u32 closed_gop_enable, u32 au_delim_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 4687915..5eed305 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -596,7 +596,7 @@
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
 		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
-		encoder->closed_gop);
+		encoder->closed_gop, encoder->avc_delimiter_enable);
 	vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
 		[ddl->command_channel],
 		encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index f68802e..3670dc81 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -27,8 +27,8 @@
 
 #define PIL_FW_SIZE 0x200000
 
-static unsigned int vidc_clk_table[4] = {
-	48000000, 133330000, 200000000, 228570000,
+static unsigned int vidc_clk_table[5] = {
+	48000000, 133330000, 200000000, 228570000, 266670000,
 };
 static unsigned int restrk_mmu_subsystem[] =	{
 		MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
@@ -629,7 +629,7 @@
 		vidc_freq = vidc_clk_table[2];
 		*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
 	} else {
-		vidc_freq = vidc_clk_table[3];
+		vidc_freq = vidc_clk_table[4];
 		*pn_set_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
 	}
 
@@ -650,6 +650,10 @@
 		VCDRES_MSG_MED("%s(): Setting vidc freq to %u\n",
 			__func__, vidc_freq);
 		if (!res_trk_sel_clk_rate(vidc_freq)) {
+			if (vidc_freq == vidc_clk_table[4]) {
+				if (res_trk_sel_clk_rate(vidc_clk_table[3]))
+					goto ret;
+			}
 			VCDRES_MSG_ERROR("%s(): res_trk_sel_clk_rate FAILED\n",
 				__func__);
 			*pn_set_perf_lvl = 0;
@@ -657,7 +661,7 @@
 		}
 	}
 #endif
-	VCDRES_MSG_MED("%s() set perl level : %d", __func__, *pn_set_perf_lvl);
+ret:	VCDRES_MSG_MED("%s() set perl level : %d", __func__, *pn_set_perf_lvl);
 	return true;
 }
 
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 31a152d..5b07403 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -444,3 +444,4 @@
 header-y += idle_stats_device.h
 header-y += genlock.h
 header-y += msm_audio_amrwb.h
+header-y += coresight-stm.h
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 754f2f3..7c7c26e 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -28,6 +28,7 @@
 	STM_OPTION_GUARANTEED		= 0x80,
 };
 
+#ifdef __KERNEL__
 #define stm_log_inv(entity_id, proto_id, data, size)			\
 	stm_trace(STM_OPTION_NONE, entity_id, proto_id, data, size)
 
@@ -56,5 +57,6 @@
 	return 0;
 }
 #endif
+#endif /* __KERNEL__ */
 
 #endif
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index b7b7d90..ca1a425 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -13,6 +13,7 @@
 	int32_t physical;
 };
 
+#ifdef __KERNEL__
 struct epm_psoc_init_resp {
 	u8	cmd;
 	u8	version;
@@ -91,7 +92,6 @@
 	uint32_t	vadc_voltage;
 };
 
-#ifdef __KERNEL__
 struct epm_chan_properties {
 	uint32_t resistorvalue;
 	uint32_t gain;
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 5c3c728..348a231 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -73,6 +73,7 @@
 	int irq_gpio;
 	u32 irq_gpio_flags;
 	int *key_codes;
+	bool need_calibration;
 
 	u8(*read_chg) (void);
 	int (*init_hw) (bool);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 85bb182..85e5002 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -39,8 +39,6 @@
 	ION_HEAP_TYPE_SYSTEM,
 	ION_HEAP_TYPE_SYSTEM_CONTIG,
 	ION_HEAP_TYPE_CARVEOUT,
-	ION_HEAP_TYPE_IOMMU,
-	ION_HEAP_TYPE_CP,
 	ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
 				 are at the end of this enum */
 	ION_NUM_HEAPS,
@@ -49,7 +47,6 @@
 #define ION_HEAP_SYSTEM_MASK		(1 << ION_HEAP_TYPE_SYSTEM)
 #define ION_HEAP_SYSTEM_CONTIG_MASK	(1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
 #define ION_HEAP_CARVEOUT_MASK		(1 << ION_HEAP_TYPE_CARVEOUT)
-#define ION_HEAP_CP_MASK		(1 << ION_HEAP_TYPE_CP)
 
 /**
  * heap flags - the lower 16 bits are used by core ion, the upper 16
@@ -60,81 +57,6 @@
 					   maintenance when the buffer is
 					   mapped for dma */
 
-/**
- * These are the only ids that should be used for Ion heap ids.
- * The ids listed are the order in which allocation will be attempted
- * if specified. Don't swap the order of heap ids unless you know what
- * you are doing!
- * Id's are spaced by purpose to allow new Id's to be inserted in-between (for
- * possible fallbacks)
- */
-
-enum ion_heap_ids {
-	INVALID_HEAP_ID = -1,
-	ION_CP_MM_HEAP_ID = 8,
-	ION_CP_MFC_HEAP_ID = 12,
-	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
-	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
-	ION_SF_HEAP_ID = 24,
-	ION_IOMMU_HEAP_ID = 25,
-	ION_QSECOM_HEAP_ID = 27,
-	ION_AUDIO_HEAP_ID = 28,
-
-	ION_MM_FIRMWARE_HEAP_ID = 29,
-	ION_SYSTEM_HEAP_ID = 30,
-
-	ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
-};
-
-enum ion_fixed_position {
-	NOT_FIXED,
-	FIXED_LOW,
-	FIXED_MIDDLE,
-	FIXED_HIGH,
-};
-
-enum cp_mem_usage {
-	VIDEO_BITSTREAM = 0x1,
-	VIDEO_PIXEL = 0x2,
-	VIDEO_NONPIXEL = 0x3,
-	MAX_USAGE = 0x4,
-	UNKNOWN = 0x7FFFFFFF,
-};
-
-/**
- * Flag to use when allocating to indicate that a heap is secure.
- */
-#define ION_SECURE (1 << ION_HEAP_ID_RESERVED)
-
-/**
- * Macro should be used with ion_heap_ids defined above.
- */
-#define ION_HEAP(bit) (1 << (bit))
-
-#define ION_VMALLOC_HEAP_NAME	"vmalloc"
-#define ION_AUDIO_HEAP_NAME	"audio"
-#define ION_SF_HEAP_NAME	"sf"
-#define ION_MM_HEAP_NAME	"mm"
-#define ION_CAMERA_HEAP_NAME	"camera_preview"
-#define ION_IOMMU_HEAP_NAME	"iommu"
-#define ION_MFC_HEAP_NAME	"mfc"
-#define ION_WB_HEAP_NAME	"wb"
-#define ION_MM_FIRMWARE_HEAP_NAME	"mm_fw"
-#define ION_QSECOM_HEAP_NAME	"qsecom"
-#define ION_FMEM_HEAP_NAME	"fmem"
-
-#define ION_SET_CACHED(__cache)		(__cache | ION_FLAG_CACHED)
-#define ION_SET_UNCACHED(__cache)	(__cache & ~ION_FLAG_CACHED)
-
-#define ION_IS_CACHED(__flags)	((__flags) & ION_FLAG_CACHED)
-
-
-/*
- * This flag allows clients when mapping into the IOMMU to specify to
- * defer un-mapping from the IOMMU until the buffer memory is freed.
- */
-#define ION_IOMMU_UNMAP_DELAYED 1
-
 #ifdef __KERNEL__
 #include <linux/err.h>
 #include <mach/ion.h>
@@ -175,72 +97,6 @@
 };
 
 /**
- * struct ion_cp_heap_pdata - defines a content protection heap in the given
- * platform
- * @permission_type:	Memory ID used to identify the memory to TZ
- * @align:		Alignment requirement for the memory
- * @secure_base:	Base address for securing the heap.
- *			Note: This might be different from actual base address
- *			of this heap in the case of a shared heap.
- * @secure_size:	Memory size for securing the heap.
- *			Note: This might be different from actual size
- *			of this heap in the case of a shared heap.
- * @reusable		Flag indicating whether this heap is reusable of not.
- *			(see FMEM)
- * @mem_is_fmem		Flag indicating whether this memory is coming from fmem
- *			or not.
- * @fixed_position	If nonzero, position in the fixed area.
- * @virt_addr:		Virtual address used when using fmem.
- * @iommu_map_all:	Indicates whether we should map whole heap into IOMMU.
- * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
- * @request_region:	function to be called when the number of allocations
- *			goes from 0 -> 1
- * @release_region:	function to be called when the number of allocations
- *			goes from 1 -> 0
- * @setup_region:	function to be called upon ion registration
- *
- */
-struct ion_cp_heap_pdata {
-	enum ion_permission_type permission_type;
-	unsigned int align;
-	ion_phys_addr_t secure_base; /* Base addr used when heap is shared */
-	size_t secure_size; /* Size used for securing heap when heap is shared*/
-	int reusable;
-	int mem_is_fmem;
-	enum ion_fixed_position fixed_position;
-	int iommu_map_all;
-	int iommu_2x_map_domain;
-	ion_virt_addr_t *virt_addr;
-	int (*request_region)(void *);
-	int (*release_region)(void *);
-	void *(*setup_region)(void);
-};
-
-/**
- * struct ion_co_heap_pdata - defines a carveout heap in the given platform
- * @adjacent_mem_id:	Id of heap that this heap must be adjacent to.
- * @align:		Alignment requirement for the memory
- * @mem_is_fmem		Flag indicating whether this memory is coming from fmem
- *			or not.
- * @fixed_position	If nonzero, position in the fixed area.
- * @request_region:	function to be called when the number of allocations
- *			goes from 0 -> 1
- * @release_region:	function to be called when the number of allocations
- *			goes from 1 -> 0
- * @setup_region:	function to be called upon ion registration
- *
- */
-struct ion_co_heap_pdata {
-	int adjacent_mem_id;
-	unsigned int align;
-	int mem_is_fmem;
-	enum ion_fixed_position fixed_position;
-	int (*request_region)(void *);
-	int (*release_region)(void *);
-	void *(*setup_region)(void);
-};
-
-/**
  * struct ion_platform_data - array of platform heaps passed from board file
  * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
  * @nr:    number of structures in the array
@@ -426,6 +282,7 @@
  *		address space will be mapped to a dummy buffer.
  * @iova - pointer to store the iova address
  * @buffer_size - pointer to store the size of the buffer
+ * @flags - flags for options to map
  * @iommu_flags - flags specific to the iommu.
  *
  * Maps the handle into the iova space specified via domain number. Iova
@@ -500,50 +357,6 @@
 			void *data);
 
 /**
- * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
- *
-  * @heap_id - heap id to secure.
- *
- * Secure a heap
- * Returns 0 on success
- */
-int msm_ion_secure_heap(int heap_id);
-
-/**
- * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap.
- *
-  * @heap_id - heap id to secure.
- *
- * Un-secure a heap
- * Returns 0 on success
- */
-int msm_ion_unsecure_heap(int heap_id);
-
-/**
- * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs
- *  Wrapper around ion_secure_heap.
- *
- * @heap_id - heap id to secure.
- * @usage - usage hint to TZ
- *
- * Secure a heap
- * Returns 0 on success
- */
-int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage);
-
-/**
- * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs.
- * Wrapper around ion_unsecure_heap.
- *
- * @heap_id - heap id to secure.
- * @usage - usage hint to TZ
- *
- * Un-secure a heap
- * Returns 0 on success
- */
-int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage);
-
-/**
  * msm_ion_do_cache_op - do cache operations.
  *
  * @client - pointer to ION client.
@@ -660,28 +473,6 @@
 	return -ENODEV;
 }
 
-static inline int msm_ion_secure_heap(int heap_id)
-{
-	return -ENODEV;
-
-}
-
-static inline int msm_ion_unsecure_heap(int heap_id)
-{
-	return -ENODEV;
-}
-
-static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
-{
-	return -ENODEV;
-}
-
-static inline int msm_ion_unsecure_heap_2_0(int heap_id,
-					enum cp_mem_usage usage)
-{
-	return -ENODEV;
-}
-
 static inline int msm_ion_do_cache_op(struct ion_client *client,
 			struct ion_handle *handle, void *vaddr,
 			unsigned long len, unsigned int cmd)
@@ -754,41 +545,6 @@
 	unsigned int cmd;
 	unsigned long arg;
 };
-
-
-/* struct ion_flush_data - data passed to ion for flushing caches
- *
- * @handle:	handle with data to flush
- * @fd:		fd to flush
- * @vaddr:	userspace virtual address mapped with mmap
- * @offset:	offset into the handle to flush
- * @length:	length of handle to flush
- *
- * Performs cache operations on the handle. If p is the start address
- * of the handle, p + offset through p + offset + length will have
- * the cache operations performed
- */
-struct ion_flush_data {
-	struct ion_handle *handle;
-	int fd;
-	void *vaddr;
-	unsigned int offset;
-	unsigned int length;
-};
-
-/* struct ion_flag_data - information about flags for this buffer
- *
- * @handle:	handle to get flags from
- * @flags:	flags of this handle
- *
- * Takes handle as an input and outputs the flags from the handle
- * in the flag field.
- */
-struct ion_flag_data {
-	struct ion_handle *handle;
-	unsigned long flags;
-};
-
 #define ION_IOC_MAGIC		'I'
 
 /**
@@ -846,34 +602,4 @@
 #define ION_IOC_CUSTOM		_IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
 
 
-/**
- * DOC: ION_IOC_CLEAN_CACHES - clean the caches
- *
- * Clean the caches of the handle specified.
- */
-#define ION_IOC_CLEAN_CACHES	_IOWR(ION_IOC_MAGIC, 20, \
-						struct ion_flush_data)
-/**
- * DOC: ION_MSM_IOC_INV_CACHES - invalidate the caches
- *
- * Invalidate the caches of the handle specified.
- */
-#define ION_IOC_INV_CACHES	_IOWR(ION_IOC_MAGIC, 21, \
-						struct ion_flush_data)
-/**
- * DOC: ION_MSM_IOC_CLEAN_CACHES - clean and invalidate the caches
- *
- * Clean and invalidate the caches of the handle specified.
- */
-#define ION_IOC_CLEAN_INV_CACHES	_IOWR(ION_IOC_MAGIC, 22, \
-						struct ion_flush_data)
-
-/**
- * DOC: ION_IOC_GET_FLAGS - get the flags of the handle
- *
- * Gets the flags of the current handle which indicate cachability,
- * secure state etc.
- */
-#define ION_IOC_GET_FLAGS		_IOWR(ION_IOC_MAGIC, 23, \
-						struct ion_flag_data)
 #endif /* _LINUX_ION_H */
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
new file mode 100644
index 0000000..c55e47e
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -0,0 +1,155 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __PM8XXX_BMS_BATTERYDATA_H
+#define __PM8XXX_BMS_BATTERYDATA_H
+
+#include <linux/errno.h>
+
+#define FCC_CC_COLS		5
+#define FCC_TEMP_COLS		8
+
+#define PC_CC_ROWS             29
+#define PC_CC_COLS             13
+
+#define PC_TEMP_ROWS		29
+#define PC_TEMP_COLS		8
+
+#define MAX_SINGLE_LUT_COLS	20
+
+struct single_row_lut {
+	int x[MAX_SINGLE_LUT_COLS];
+	int y[MAX_SINGLE_LUT_COLS];
+	int cols;
+};
+
+/**
+ * struct sf_lut -
+ * @rows:	number of percent charge entries should be <= PC_CC_ROWS
+ * @cols:	number of charge cycle entries should be <= PC_CC_COLS
+ * @row_entries:	the charge cycles/temperature at which sf data
+ *			is available in the table.
+ *		The charge cycles must be in increasing order from 0 to rows.
+ * @percent:	the percent charge at which sf data is available in the table
+ *		The  percentcharge must be in decreasing order from 0 to cols.
+ * @sf:		the scaling factor data
+ */
+struct sf_lut {
+	int rows;
+	int cols;
+	int row_entries[PC_CC_COLS];
+	int percent[PC_CC_ROWS];
+	int sf[PC_CC_ROWS][PC_CC_COLS];
+};
+
+/**
+ * struct pc_temp_ocv_lut -
+ * @rows:	number of percent charge entries should be <= PC_TEMP_ROWS
+ * @cols:	number of temperature entries should be <= PC_TEMP_COLS
+ * @temp:	the temperatures at which ocv data is available in the table
+ *		The temperatures must be in increasing order from 0 to rows.
+ * @percent:	the percent charge at which ocv data is available in the table
+ *		The  percentcharge must be in decreasing order from 0 to cols.
+ * @ocv:	the open circuit voltage
+ */
+struct pc_temp_ocv_lut {
+	int rows;
+	int cols;
+	int temp[PC_TEMP_COLS];
+	int percent[PC_TEMP_ROWS];
+	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
+};
+
+enum battery_type {
+	BATT_UNKNOWN = 0,
+	BATT_PALLADIUM,
+	BATT_DESAY,
+};
+
+/**
+ * struct bms_battery_data -
+ * @fcc:		full charge capacity (mAmpHour)
+ * @fcc_temp_lut:	table to get fcc at a given temp
+ * @pc_temp_ocv_lut:	table to get percent charge given batt temp and cycles
+ * @pc_sf_lut:		table to get percent charge scaling factor given cycles
+ *			and percent charge
+ * @rbatt_sf_lut:	table to get battery resistance scaling factor given
+ *			temperature and percent charge
+ * @default_rbatt_mohm:	the default value of battery resistance to use when
+ *			readings from bms are not available.
+ * @delta_rbatt_mohm:	the resistance to be added towards lower soc to
+ *			compensate for battery capacitance.
+ */
+
+struct bms_battery_data {
+	unsigned int		fcc;
+	struct single_row_lut	*fcc_temp_lut;
+	struct single_row_lut	*fcc_sf_lut;
+	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
+	struct sf_lut		*pc_sf_lut;
+	struct sf_lut		*rbatt_sf_lut;
+	int			default_rbatt_mohm;
+	int			delta_rbatt_mohm;
+};
+
+#if defined(CONFIG_PM8921_BMS) || \
+	defined(CONFIG_PM8921_BMS_MODULE)
+extern struct bms_battery_data  palladium_1500_data;
+extern struct bms_battery_data  desay_5200_data;
+
+int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp);
+int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc);
+int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
+				int cycles);
+int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int ocv);
+int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+				int batt_temp_degc, int pc);
+int linear_interpolate(int y0, int x0, int y1, int x1, int x);
+int is_between(int left, int right, int value);
+#else
+static inline int interpolate_fcc(struct single_row_lut *fcc_temp_lut,
+			int batt_temp)
+{
+	return -EINVAL;
+}
+static inline int interpolate_scalingfactor(struct sf_lut *sf_lut,
+			int row_entry, int pc)
+{
+	return -EINVAL;
+}
+static inline int interpolate_scalingfactor_fcc(
+			struct single_row_lut *fcc_sf_lut, int cycles)
+{
+	return -EINVAL;
+}
+static inline int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+			int batt_temp_degc, int ocv)
+{
+	return -EINVAL;
+}
+static inline int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+			int batt_temp_degc, int pc)
+{
+	return -EINVAL;
+}
+static inline int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	return -EINVAL;
+}
+static inline int is_between(int left, int right, int value)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index a73a284..5f2fe9f 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -14,87 +14,10 @@
 #define __PM8XXX_BMS_H
 
 #include <linux/errno.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 #define PM8921_BMS_DEV_NAME	"pm8921-bms"
 
-#define FCC_CC_COLS		5
-#define FCC_TEMP_COLS		8
-
-#define PC_CC_ROWS             29
-#define PC_CC_COLS             13
-
-#define PC_TEMP_ROWS		29
-#define PC_TEMP_COLS		8
-
-#define MAX_SINGLE_LUT_COLS	20
-
-struct single_row_lut {
-	int x[MAX_SINGLE_LUT_COLS];
-	int y[MAX_SINGLE_LUT_COLS];
-	int cols;
-};
-
-/**
- * struct sf_lut -
- * @rows:	number of percent charge entries should be <= PC_CC_ROWS
- * @cols:	number of charge cycle entries should be <= PC_CC_COLS
- * @row_entries:	the charge cycles/temperature at which sf data
- *			is available in the table.
- *		The charge cycles must be in increasing order from 0 to rows.
- * @percent:	the percent charge at which sf data is available in the table
- *		The  percentcharge must be in decreasing order from 0 to cols.
- * @sf:		the scaling factor data
- */
-struct sf_lut {
-	int rows;
-	int cols;
-	int row_entries[PC_CC_COLS];
-	int percent[PC_CC_ROWS];
-	int sf[PC_CC_ROWS][PC_CC_COLS];
-};
-
-/**
- * struct pc_temp_ocv_lut -
- * @rows:	number of percent charge entries should be <= PC_TEMP_ROWS
- * @cols:	number of temperature entries should be <= PC_TEMP_COLS
- * @temp:	the temperatures at which ocv data is available in the table
- *		The temperatures must be in increasing order from 0 to rows.
- * @percent:	the percent charge at which ocv data is available in the table
- *		The  percentcharge must be in decreasing order from 0 to cols.
- * @ocv:	the open circuit voltage
- */
-struct pc_temp_ocv_lut {
-	int rows;
-	int cols;
-	int temp[PC_TEMP_COLS];
-	int percent[PC_TEMP_ROWS];
-	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
-};
-
-/**
- * struct pm8921_bms_battery_data -
- * @fcc:		full charge capacity (mAmpHour)
- * @fcc_temp_lut:	table to get fcc at a given temp
- * @pc_temp_ocv_lut:	table to get percent charge given batt temp and cycles
- * @pc_sf_lut:		table to get percent charge scaling factor given cycles
- *			and percent charge
- * @rbatt_sf_lut:	table to get battery resistance scaling factor given
- *			temperature and percent charge
- * @default_rbatt_mohm:	the default value of battery resistance to use when
- *			readings from bms are not available.
- * @delta_rbatt_mohm:	the resistance to be added towards lower soc to
- *			compensate for battery capacitance.
- */
-struct pm8921_bms_battery_data {
-	unsigned int		fcc;
-	struct single_row_lut	*fcc_temp_lut;
-	struct single_row_lut	*fcc_sf_lut;
-	struct pc_temp_ocv_lut	*pc_temp_ocv_lut;
-	struct sf_lut		*pc_sf_lut;
-	struct sf_lut		*rbatt_sf_lut;
-	int			default_rbatt_mohm;
-	int			delta_rbatt_mohm;
-};
 
 struct pm8xxx_bms_core_data {
 	unsigned int	batt_temp_channel;
@@ -104,12 +27,6 @@
 	unsigned int	batt_id_channel;
 };
 
-enum battery_type {
-	BATT_UNKNOWN = 0,
-	BATT_PALLADIUM,
-	BATT_DESAY,
-};
-
 /**
  * struct pm8921_bms_platform_data -
  * @batt_type:		allows to force chose battery calibration data
@@ -137,8 +54,6 @@
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
-extern struct pm8921_bms_battery_data  palladium_1500_data;
-extern struct pm8921_bms_battery_data  desay_5200_data;
 /**
  * pm8921_bms_get_vsense_avg - return the voltage across the sense
  *				resitor in microvolts
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 7b389c5..0e86f2a 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -63,6 +63,8 @@
  * @ttrkl_time:		max trckl charging time in minutes
  *			valid range 1 to 64 mins. PON default 15 min
  * @update_time:	how often the userland be updated of the charging (msec)
+ * @alarm_low_mv:	the voltage (mV) when low battery alarm is triggered
+ * @alarm_high_mv:	the voltage (mV) when high battery alarm is triggered
  * @max_voltage:	the max voltage (mV) the battery should be charged up to
  * @min_voltage:	the voltage (mV) where charging method switches from
  *			trickle to fast. This is also the minimum voltage the
@@ -128,6 +130,8 @@
 	unsigned int			max_voltage;
 	unsigned int			min_voltage;
 	unsigned int			uvd_thresh_voltage;
+	unsigned int			alarm_low_mv;
+	unsigned int			alarm_high_mv;
 	unsigned int			resume_voltage_delta;
 	unsigned int			term_current;
 	int				cool_temp;
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index f6d164d..c306c75 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -37,6 +37,12 @@
 #define SITAR_IS_1P1(ver) \
 	((ver == SITAR_VERSION_1P1) ? 1 : 0)
 
+
+#define TAIKO_VERSION_1_0	0
+#define TAIKO_IS_1_0(ver) \
+	((ver == TAIKO_VERSION_1_0) ? 1 : 0)
+
+
 enum {
 	TABLA_IRQ_SLIMBUS = 0,
 	TABLA_IRQ_MBHC_REMOVAL,
diff --git a/include/linux/mfd/wcd9xxx/wcd9320_registers.h b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
index 5725e6e..4b8626a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9320_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
@@ -701,45 +701,45 @@
 #define TAIKO_A_CDC_TX10_VOL_CTL_CFG			(0x26A)
 #define TAIKO_A_CDC_TX10_VOL_CTL_CFG__POR				(0x00)
 #define TAIKO_A_CDC_TX1_MUX_CTL			(0x223)
-#define TAIKO_A_CDC_TX1_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX1_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX2_MUX_CTL			(0x22B)
-#define TAIKO_A_CDC_TX2_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX2_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX3_MUX_CTL			(0x233)
-#define TAIKO_A_CDC_TX3_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX3_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX4_MUX_CTL			(0x23B)
-#define TAIKO_A_CDC_TX4_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX4_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX5_MUX_CTL			(0x243)
-#define TAIKO_A_CDC_TX5_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX5_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX6_MUX_CTL			(0x24B)
-#define TAIKO_A_CDC_TX6_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX6_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX7_MUX_CTL			(0x253)
-#define TAIKO_A_CDC_TX7_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX7_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX8_MUX_CTL			(0x25B)
-#define TAIKO_A_CDC_TX8_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX8_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX9_MUX_CTL			(0x263)
-#define TAIKO_A_CDC_TX9_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX9_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX10_MUX_CTL			(0x26B)
-#define TAIKO_A_CDC_TX10_MUX_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX10_MUX_CTL__POR				(0x08)
 #define TAIKO_A_CDC_TX1_CLK_FS_CTL			(0x224)
-#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX2_CLK_FS_CTL			(0x22C)
-#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX3_CLK_FS_CTL			(0x234)
-#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX4_CLK_FS_CTL			(0x23C)
-#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX5_CLK_FS_CTL			(0x244)
-#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX6_CLK_FS_CTL			(0x24C)
-#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX7_CLK_FS_CTL			(0x254)
-#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX8_CLK_FS_CTL			(0x25C)
-#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX9_CLK_FS_CTL			(0x264)
-#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX10_CLK_FS_CTL			(0x26C)
-#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR				(0x03)
 #define TAIKO_A_CDC_TX1_DMIC_CTL			(0x225)
 #define TAIKO_A_CDC_TX1_DMIC_CTL__POR				(0x00)
 #define TAIKO_A_CDC_TX2_DMIC_CTL			(0x22D)
@@ -779,9 +779,9 @@
 #define TAIKO_A_CDC_SRC2_PDA_CFG			(0x2A8)
 #define TAIKO_A_CDC_SRC2_PDA_CFG__POR				(0x00)
 #define TAIKO_A_CDC_SRC1_FS_CTL			(0x2A1)
-#define TAIKO_A_CDC_SRC1_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_SRC1_FS_CTL__POR				(0x1B)
 #define TAIKO_A_CDC_SRC2_FS_CTL			(0x2A9)
-#define TAIKO_A_CDC_SRC2_FS_CTL__POR				(0x00)
+#define TAIKO_A_CDC_SRC2_FS_CTL__POR				(0x1B)
 #define TAIKO_A_CDC_RX1_B1_CTL			(0x2B0)
 #define TAIKO_A_CDC_RX1_B1_CTL__POR				(0x00)
 #define TAIKO_A_CDC_RX2_B1_CTL			(0x2B8)
@@ -839,33 +839,33 @@
 #define TAIKO_A_CDC_RX7_B4_CTL			(0x2E3)
 #define TAIKO_A_CDC_RX7_B4_CTL__POR				(0x00)
 #define TAIKO_A_CDC_RX1_B5_CTL			(0x2B4)
-#define TAIKO_A_CDC_RX1_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX1_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX2_B5_CTL			(0x2BC)
-#define TAIKO_A_CDC_RX2_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX2_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX3_B5_CTL			(0x2C4)
-#define TAIKO_A_CDC_RX3_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX3_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX4_B5_CTL			(0x2CC)
-#define TAIKO_A_CDC_RX4_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX4_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX5_B5_CTL			(0x2D4)
-#define TAIKO_A_CDC_RX5_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX5_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX6_B5_CTL			(0x2DC)
-#define TAIKO_A_CDC_RX6_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX6_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX7_B5_CTL			(0x2E4)
-#define TAIKO_A_CDC_RX7_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX7_B5_CTL__POR				(0x78)
 #define TAIKO_A_CDC_RX1_B6_CTL			(0x2B5)
-#define TAIKO_A_CDC_RX1_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX1_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX2_B6_CTL			(0x2BD)
-#define TAIKO_A_CDC_RX2_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX2_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX3_B6_CTL			(0x2C5)
-#define TAIKO_A_CDC_RX3_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX3_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX4_B6_CTL			(0x2CD)
-#define TAIKO_A_CDC_RX4_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX4_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX5_B6_CTL			(0x2D5)
-#define TAIKO_A_CDC_RX5_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX5_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX6_B6_CTL			(0x2DD)
-#define TAIKO_A_CDC_RX6_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX6_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX7_B6_CTL			(0x2E5)
-#define TAIKO_A_CDC_RX7_B6_CTL__POR				(0x00)
+#define TAIKO_A_CDC_RX7_B6_CTL__POR				(0x80)
 #define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
 #define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL__POR				(0x00)
 #define TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL			(0x2BE)
@@ -1041,9 +1041,9 @@
 #define TAIKO_A_CDC_IIR2_GAIN_B8_CTL			(0x357)
 #define TAIKO_A_CDC_IIR2_GAIN_B8_CTL__POR				(0x00)
 #define TAIKO_A_CDC_IIR1_CTL			(0x348)
-#define TAIKO_A_CDC_IIR1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_IIR1_CTL__POR				(0x40)
 #define TAIKO_A_CDC_IIR2_CTL			(0x358)
-#define TAIKO_A_CDC_IIR2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_IIR2_CTL__POR				(0x40)
 #define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL			(0x349)
 #define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL__POR				(0x00)
 #define TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL			(0x359)
@@ -1059,35 +1059,35 @@
 #define TAIKO_A_CDC_TOP_GAIN_UPDATE			(0x360)
 #define TAIKO_A_CDC_TOP_GAIN_UPDATE__POR				(0x00)
 #define TAIKO_A_CDC_COMP0_B1_CTL			(0x368)
-#define TAIKO_A_CDC_COMP0_B1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B1_CTL__POR				(0x30)
 #define TAIKO_A_CDC_COMP1_B1_CTL			(0x370)
-#define TAIKO_A_CDC_COMP1_B1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B1_CTL__POR				(0x30)
 #define TAIKO_A_CDC_COMP2_B1_CTL			(0x378)
-#define TAIKO_A_CDC_COMP2_B1_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B1_CTL__POR				(0x30)
 #define TAIKO_A_CDC_COMP0_B2_CTL			(0x369)
-#define TAIKO_A_CDC_COMP0_B2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B2_CTL__POR				(0xB5)
 #define TAIKO_A_CDC_COMP1_B2_CTL			(0x371)
-#define TAIKO_A_CDC_COMP1_B2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B2_CTL__POR				(0xB5)
 #define TAIKO_A_CDC_COMP2_B2_CTL			(0x379)
-#define TAIKO_A_CDC_COMP2_B2_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B2_CTL__POR				(0xB5)
 #define TAIKO_A_CDC_COMP0_B3_CTL			(0x36A)
-#define TAIKO_A_CDC_COMP0_B3_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B3_CTL__POR				(0x28)
 #define TAIKO_A_CDC_COMP1_B3_CTL			(0x372)
-#define TAIKO_A_CDC_COMP1_B3_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B3_CTL__POR				(0x28)
 #define TAIKO_A_CDC_COMP2_B3_CTL			(0x37A)
-#define TAIKO_A_CDC_COMP2_B3_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B3_CTL__POR				(0x28)
 #define TAIKO_A_CDC_COMP0_B4_CTL			(0x36B)
-#define TAIKO_A_CDC_COMP0_B4_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B4_CTL__POR				(0x3C)
 #define TAIKO_A_CDC_COMP1_B4_CTL			(0x373)
-#define TAIKO_A_CDC_COMP1_B4_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B4_CTL__POR				(0x3C)
 #define TAIKO_A_CDC_COMP2_B4_CTL			(0x37B)
-#define TAIKO_A_CDC_COMP2_B4_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B4_CTL__POR				(0x3C)
 #define TAIKO_A_CDC_COMP0_B5_CTL			(0x36C)
-#define TAIKO_A_CDC_COMP0_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_B5_CTL__POR				(0x1F)
 #define TAIKO_A_CDC_COMP1_B5_CTL			(0x374)
-#define TAIKO_A_CDC_COMP1_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_B5_CTL__POR				(0x1F)
 #define TAIKO_A_CDC_COMP2_B5_CTL			(0x37C)
-#define TAIKO_A_CDC_COMP2_B5_CTL__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_B5_CTL__POR				(0x1F)
 #define TAIKO_A_CDC_COMP0_B6_CTL			(0x36D)
 #define TAIKO_A_CDC_COMP0_B6_CTL__POR				(0x00)
 #define TAIKO_A_CDC_COMP1_B6_CTL			(0x375)
@@ -1095,17 +1095,17 @@
 #define TAIKO_A_CDC_COMP2_B6_CTL			(0x37D)
 #define TAIKO_A_CDC_COMP2_B6_CTL__POR				(0x00)
 #define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS			(0x36E)
-#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS			(0x376)
-#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS			(0x37E)
-#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAIKO_A_CDC_COMP0_FS_CFG			(0x36F)
-#define TAIKO_A_CDC_COMP0_FS_CFG__POR				(0x00)
+#define TAIKO_A_CDC_COMP0_FS_CFG__POR				(0x03)
 #define TAIKO_A_CDC_COMP1_FS_CFG			(0x377)
-#define TAIKO_A_CDC_COMP1_FS_CFG__POR				(0x00)
+#define TAIKO_A_CDC_COMP1_FS_CFG__POR				(0x03)
 #define TAIKO_A_CDC_COMP2_FS_CFG			(0x37F)
-#define TAIKO_A_CDC_COMP2_FS_CFG__POR				(0x00)
+#define TAIKO_A_CDC_COMP2_FS_CFG__POR				(0x03)
 #define TAIKO_A_CDC_CONN_RX1_B1_CTL			(0x380)
 #define TAIKO_A_CDC_CONN_RX1_B1_CTL__POR				(0x00)
 #define TAIKO_A_CDC_CONN_RX1_B2_CTL			(0x381)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 87e06ed..0330dfb 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -209,25 +209,6 @@
 #define MMC_BLK_DATA_AREA_GP	(1<<2)
 };
 
-enum mmc_packed_stop_reasons {
-	EXCEEDS_SEGMENTS = 0,
-	EXCEEDS_SECTORS,
-	WRONG_DATA_DIR,
-	FLUSH_OR_DISCARD,
-	EMPTY_QUEUE,
-	REL_WRITE,
-	THRESHOLD,
-	MAX_REASONS,
-};
-
-struct mmc_wr_pack_stats {
-	u32 *packing_events;
-	u32 pack_stop_reason[MAX_REASONS];
-	spinlock_t lock;
-	bool enabled;
-	bool print_in_read;
-};
-
 /*
  * MMC device
  */
@@ -302,7 +283,6 @@
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
 	unsigned int    nr_parts;
 
-	struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
 };
 
 /*
@@ -320,6 +300,11 @@
 	card->nr_parts++;
 }
 
+static inline bool mmc_large_sec(struct mmc_card *card)
+{
+	return card->ext_csd.data_sector_size == 4096;
+}
+
 /*
  *  The world is not perfect and supplies us with broken mmc/sdio devices.
  *  For at least some of these bugs we need a work-around.
@@ -527,8 +512,4 @@
 extern void mmc_fixup_device(struct mmc_card *card,
 			     const struct mmc_fixup *table);
 
-extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
-			struct mmc_card *card);
-extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
-
 #endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index dcd9a6f..714cc76 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -245,8 +245,8 @@
 #define MMC_CAP2_PACKED_WR	(1 << 11)	/* Allow packed write */
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR) /* Allow packed commands */
-#define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
 #define MMC_CAP2_SANITIZE	(1 << 13)		/* Support Sanitize */
+#define MMC_CAP2_INIT_BKOPS	    (1 << 15)	/* Need to set BKOPS_EN */
 #define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND	(1 << 16)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 87cdba8..92888c3 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -141,7 +141,6 @@
 #define R1_SWITCH_ERROR		(1 << 7)	/* sx, c */
 #define R1_EXCEPTION_EVENT	(1 << 6)	/* sx, a */
 #define R1_APP_CMD		(1 << 5)	/* sr, c */
-#define R1_EXP_EVENT		(1 << 6)	/* sr, a */
 
 #define R1_STATE_IDLE	0
 #define R1_STATE_READY	1
@@ -400,24 +399,25 @@
 #define EXT_CSD_PWR_CL_8BIT_SHIFT	4
 #define EXT_CSD_PWR_CL_4BIT_SHIFT	0
 
-#define EXT_CSD_PACKED_EVENT_EN	(1 << 3)
-
-#define EXT_CSD_PACKED_GENERIC_ERROR	(1 << 0)
-#define EXT_CSD_PACKED_INDEXED_ERROR	(1 << 1)
-
 /*
  * EXCEPTION_EVENT_STATUS field
  */
 #define EXT_CSD_URGENT_BKOPS		BIT(0)
 #define EXT_CSD_DYNCAP_NEEDED		BIT(1)
 #define EXT_CSD_SYSPOOL_EXHAUSTED	BIT(2)
-#define EXT_CSD_PACKED_FAILURE		BIT(3)
 
 /*
  * BKOPS status level
  */
 #define EXT_CSD_BKOPS_LEVEL_2		0x2
 
+#define EXT_CSD_PACKED_EVENT_EN	(1 << 3)
+
+#define EXT_CSD_PACKED_FAILURE	(1 << 3)
+
+#define EXT_CSD_PACKED_GENERIC_ERROR	(1 << 0)
+#define EXT_CSD_PACKED_INDEXED_ERROR	(1 << 1)
+
 /*
  * MMC_SWITCH access modes
  */
diff --git a/include/linux/msm_charm.h b/include/linux/msm_charm.h
index 44d2553..1d1f3bb 100644
--- a/include/linux/msm_charm.h
+++ b/include/linux/msm_charm.h
@@ -12,6 +12,7 @@
 #define WAIT_FOR_RESTART	_IOR(CHARM_CODE, 7, int)
 #define GET_DLOAD_STATUS	_IOR(CHARM_CODE, 8, int)
 #define IMAGE_UPGRADE		_IOW(CHARM_CODE, 9, int)
+#define SHUTDOWN_CHARM		_IOW(CHARM_CODE, 10, int)
 
 enum charm_boot_type {
 	CHARM_NORMAL_BOOT = 0,
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index e7959d1..21000f9 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -18,4 +18,294 @@
 
 #include <linux/ion.h>
 
+enum msm_ion_heap_types {
+	ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1,
+	ION_HEAP_TYPE_IOMMU = ION_HEAP_TYPE_MSM_START,
+	ION_HEAP_TYPE_CP,
+};
+
+/**
+ * These are the only ids that should be used for Ion heap ids.
+ * The ids listed are the order in which allocation will be attempted
+ * if specified. Don't swap the order of heap ids unless you know what
+ * you are doing!
+ * Id's are spaced by purpose to allow new Id's to be inserted in-between (for
+ * possible fallbacks)
+ */
+
+enum ion_heap_ids {
+	INVALID_HEAP_ID = -1,
+	ION_CP_MM_HEAP_ID = 8,
+	ION_CP_MFC_HEAP_ID = 12,
+	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
+	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
+	ION_SF_HEAP_ID = 24,
+	ION_IOMMU_HEAP_ID = 25,
+	ION_QSECOM_HEAP_ID = 27,
+	ION_AUDIO_HEAP_ID = 28,
+
+	ION_MM_FIRMWARE_HEAP_ID = 29,
+	ION_SYSTEM_HEAP_ID = 30,
+
+	ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
+};
+
+enum ion_fixed_position {
+	NOT_FIXED,
+	FIXED_LOW,
+	FIXED_MIDDLE,
+	FIXED_HIGH,
+};
+
+enum cp_mem_usage {
+	VIDEO_BITSTREAM = 0x1,
+	VIDEO_PIXEL = 0x2,
+	VIDEO_NONPIXEL = 0x3,
+	MAX_USAGE = 0x4,
+	UNKNOWN = 0x7FFFFFFF,
+};
+
+#define ION_HEAP_CP_MASK		(1 << ION_HEAP_TYPE_CP)
+
+/**
+ * Flag to use when allocating to indicate that a heap is secure.
+ */
+#define ION_SECURE (1 << ION_HEAP_ID_RESERVED)
+
+/**
+ * Macro should be used with ion_heap_ids defined above.
+ */
+#define ION_HEAP(bit) (1 << (bit))
+
+#define ION_VMALLOC_HEAP_NAME	"vmalloc"
+#define ION_AUDIO_HEAP_NAME	"audio"
+#define ION_SF_HEAP_NAME	"sf"
+#define ION_MM_HEAP_NAME	"mm"
+#define ION_CAMERA_HEAP_NAME	"camera_preview"
+#define ION_IOMMU_HEAP_NAME	"iommu"
+#define ION_MFC_HEAP_NAME	"mfc"
+#define ION_WB_HEAP_NAME	"wb"
+#define ION_MM_FIRMWARE_HEAP_NAME	"mm_fw"
+#define ION_QSECOM_HEAP_NAME	"qsecom"
+#define ION_FMEM_HEAP_NAME	"fmem"
+
+#define ION_SET_CACHED(__cache)		(__cache | ION_FLAG_CACHED)
+#define ION_SET_UNCACHED(__cache)	(__cache & ~ION_FLAG_CACHED)
+
+#define ION_IS_CACHED(__flags)	((__flags) & ION_FLAG_CACHED)
+
+#ifdef __KERNEL__
+
+/*
+ * This flag allows clients when mapping into the IOMMU to specify to
+ * defer un-mapping from the IOMMU until the buffer memory is freed.
+ */
+#define ION_IOMMU_UNMAP_DELAYED 1
+
+/**
+ * struct ion_cp_heap_pdata - defines a content protection heap in the given
+ * platform
+ * @permission_type:	Memory ID used to identify the memory to TZ
+ * @align:		Alignment requirement for the memory
+ * @secure_base:	Base address for securing the heap.
+ *			Note: This might be different from actual base address
+ *			of this heap in the case of a shared heap.
+ * @secure_size:	Memory size for securing the heap.
+ *			Note: This might be different from actual size
+ *			of this heap in the case of a shared heap.
+ * @reusable		Flag indicating whether this heap is reusable of not.
+ *			(see FMEM)
+ * @mem_is_fmem		Flag indicating whether this memory is coming from fmem
+ *			or not.
+ * @fixed_position	If nonzero, position in the fixed area.
+ * @virt_addr:		Virtual address used when using fmem.
+ * @iommu_map_all:	Indicates whether we should map whole heap into IOMMU.
+ * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
+ * @request_region:	function to be called when the number of allocations
+ *			goes from 0 -> 1
+ * @release_region:	function to be called when the number of allocations
+ *			goes from 1 -> 0
+ * @setup_region:	function to be called upon ion registration
+ * @memory_type:Memory type used for the heap
+ *
+ */
+struct ion_cp_heap_pdata {
+	enum ion_permission_type permission_type;
+	unsigned int align;
+	ion_phys_addr_t secure_base; /* Base addr used when heap is shared */
+	size_t secure_size; /* Size used for securing heap when heap is shared*/
+	int reusable;
+	int mem_is_fmem;
+	enum ion_fixed_position fixed_position;
+	int iommu_map_all;
+	int iommu_2x_map_domain;
+	ion_virt_addr_t *virt_addr;
+	int (*request_region)(void *);
+	int (*release_region)(void *);
+	void *(*setup_region)(void);
+	enum ion_memory_types memory_type;
+};
+
+/**
+ * struct ion_co_heap_pdata - defines a carveout heap in the given platform
+ * @adjacent_mem_id:	Id of heap that this heap must be adjacent to.
+ * @align:		Alignment requirement for the memory
+ * @mem_is_fmem		Flag indicating whether this memory is coming from fmem
+ *			or not.
+ * @fixed_position	If nonzero, position in the fixed area.
+ * @request_region:	function to be called when the number of allocations
+ *			goes from 0 -> 1
+ * @release_region:	function to be called when the number of allocations
+ *			goes from 1 -> 0
+ * @setup_region:	function to be called upon ion registration
+ * @memory_type:Memory type used for the heap
+ *
+ */
+struct ion_co_heap_pdata {
+	int adjacent_mem_id;
+	unsigned int align;
+	int mem_is_fmem;
+	enum ion_fixed_position fixed_position;
+	int (*request_region)(void *);
+	int (*release_region)(void *);
+	void *(*setup_region)(void);
+	enum ion_memory_types memory_type;
+};
+
+#ifdef CONFIG_ION
+/**
+ * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
+ *
+  * @heap_id - heap id to secure.
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap(int heap_id);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap.
+ *
+  * @heap_id - heap id to secure.
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap(int heap_id);
+
+/**
+ * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs
+ *  Wrapper around ion_secure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs.
+ * Wrapper around ion_unsecure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+#else
+static inline int msm_ion_secure_heap(int heap_id)
+{
+	return -ENODEV;
+
+}
+
+static inline int msm_ion_unsecure_heap(int heap_id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+	return -ENODEV;
+}
+
+static inline int msm_ion_unsecure_heap_2_0(int heap_id,
+					enum cp_mem_usage usage)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_ION */
+
+#endif /* __KERNEL */
+
+/* struct ion_flush_data - data passed to ion for flushing caches
+ *
+ * @handle:	handle with data to flush
+ * @fd:		fd to flush
+ * @vaddr:	userspace virtual address mapped with mmap
+ * @offset:	offset into the handle to flush
+ * @length:	length of handle to flush
+ *
+ * Performs cache operations on the handle. If p is the start address
+ * of the handle, p + offset through p + offset + length will have
+ * the cache operations performed
+ */
+struct ion_flush_data {
+	struct ion_handle *handle;
+	int fd;
+	void *vaddr;
+	unsigned int offset;
+	unsigned int length;
+};
+
+/* struct ion_flag_data - information about flags for this buffer
+ *
+ * @handle:	handle to get flags from
+ * @flags:	flags of this handle
+ *
+ * Takes handle as an input and outputs the flags from the handle
+ * in the flag field.
+ */
+struct ion_flag_data {
+	struct ion_handle *handle;
+	unsigned long flags;
+};
+
+#define ION_IOC_MSM_MAGIC 'M'
+
+/**
+ * DOC: ION_IOC_CLEAN_CACHES - clean the caches
+ *
+ * Clean the caches of the handle specified.
+ */
+#define ION_IOC_CLEAN_CACHES	_IOWR(ION_IOC_MSM_MAGIC, 0, \
+						struct ion_flush_data)
+/**
+ * DOC: ION_IOC_INV_CACHES - invalidate the caches
+ *
+ * Invalidate the caches of the handle specified.
+ */
+#define ION_IOC_INV_CACHES	_IOWR(ION_IOC_MSM_MAGIC, 1, \
+						struct ion_flush_data)
+/**
+ * DOC: ION_IOC_CLEAN_INV_CACHES - clean and invalidate the caches
+ *
+ * Clean and invalidate the caches of the handle specified.
+ */
+#define ION_IOC_CLEAN_INV_CACHES	_IOWR(ION_IOC_MSM_MAGIC, 2, \
+						struct ion_flush_data)
+
+/**
+ * DOC: ION_IOC_GET_FLAGS - get the flags of the handle
+ *
+ * Gets the flags of the current handle which indicate cachability,
+ * secure state etc.
+ */
+#define ION_IOC_GET_FLAGS		_IOWR(ION_IOC_MSM_MAGIC, 3, \
+						struct ion_flag_data)
+
 #endif
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 71ff639..5e1395e 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
 #define _MSM_KGSL_H
 
 #define KGSL_VERSION_MAJOR        3
-#define KGSL_VERSION_MINOR        12
+#define KGSL_VERSION_MINOR        13
 
 /*context flags */
 #define KGSL_CONTEXT_SAVE_GMEM		0x00000001
@@ -18,6 +18,33 @@
 /* Memory allocayion flags */
 #define KGSL_MEMFLAGS_GPUREADONLY	0x01000000
 
+#define KGSL_MEMTYPE_MASK		0x0000FF00
+#define KGSL_MEMTYPE_SHIFT		8
+
+/* Memory types for which allocations are made */
+#define KGSL_MEMTYPE_OBJECTANY			0
+#define KGSL_MEMTYPE_FRAMEBUFFER		1
+#define KGSL_MEMTYPE_RENDERBUFFER		2
+#define KGSL_MEMTYPE_ARRAYBUFFER		3
+#define KGSL_MEMTYPE_ELEMENTARRAYBUFFER		4
+#define KGSL_MEMTYPE_VERTEXARRAYBUFFER		5
+#define KGSL_MEMTYPE_TEXTURE			6
+#define KGSL_MEMTYPE_SURFACE			7
+#define KGSL_MEMTYPE_EGL_SURFACE		8
+#define KGSL_MEMTYPE_GL				9
+#define KGSL_MEMTYPE_CL				10
+#define KGSL_MEMTYPE_CL_BUFFER_MAP		11
+#define KGSL_MEMTYPE_CL_BUFFER_NOMAP		12
+#define KGSL_MEMTYPE_CL_IMAGE_MAP		13
+#define KGSL_MEMTYPE_CL_IMAGE_NOMAP		14
+#define KGSL_MEMTYPE_CL_KERNEL_STACK		15
+#define KGSL_MEMTYPE_COMMAND			16
+#define KGSL_MEMTYPE_2D				17
+#define KGSL_MEMTYPE_EGL_IMAGE			18
+#define KGSL_MEMTYPE_EGL_SHADOW			19
+#define KGSL_MEMTYPE_MULTISAMPLE		20
+#define KGSL_MEMTYPE_KERNEL			255
+
 /* generic flag values */
 #define KGSL_FLAGS_NORMALMODE  0x00000000
 #define KGSL_FLAGS_SAFEMODE    0x00000001
@@ -278,8 +305,7 @@
 	unsigned int offset;
 	unsigned int hostptr;   /*input param */
 	enum kgsl_user_mem_type memtype;
-	unsigned int reserved;	/* May be required to add
-				params for another mem type */
+	unsigned int flags;
 };
 
 #define IOCTL_KGSL_MAP_USER_MEM \
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index d03ecfa..1cdc434 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -71,6 +71,8 @@
 #define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
 #define MSMFB_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
 #define MSMFB_METADATA_SET  _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata)
+#define MSMFB_OVERLAY_COMMIT      _IOW(MSMFB_IOCTL_MAGIC, 163, unsigned int)
+
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701
@@ -276,6 +278,8 @@
 #define MDP_PP_OPS_READ 0x2
 #define MDP_PP_OPS_WRITE 0x4
 #define MDP_PP_OPS_DISABLE 0x8
+#define MDP_PP_IGC_FLAG_ROM0	0x10
+#define MDP_PP_IGC_FLAG_ROM1	0x20
 
 struct mdp_qseed_cfg {
 	uint32_t table_num;
@@ -405,7 +409,7 @@
 
 struct mdp_histogram_data {
 	uint32_t block;
-	uint8_t bin_cnt;
+	uint32_t bin_cnt;
 	uint32_t *c0;
 	uint32_t *c1;
 	uint32_t *c2;
@@ -422,6 +426,8 @@
 	struct mdp_pcc_coeff r, g, b;
 };
 
+#define MDP_GAMUT_TABLE_NUM		8
+
 enum {
 	mdp_lut_igc,
 	mdp_lut_pgc,
@@ -484,6 +490,24 @@
 	uint32_t cont_adj;
 };
 
+struct mdp_dither_cfg_data {
+	uint32_t block;
+	uint32_t flags;
+	uint32_t g_y_depth;
+	uint32_t r_cr_depth;
+	uint32_t b_cb_depth;
+};
+
+struct mdp_gamut_cfg_data {
+	uint32_t block;
+	uint32_t flags;
+	uint32_t gamut_first;
+	uint32_t tbl_size[MDP_GAMUT_TABLE_NUM];
+	uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+};
+
 enum {
 	mdp_op_pcc_cfg,
 	mdp_op_csc_cfg,
@@ -491,6 +515,8 @@
 	mdp_op_qseed_cfg,
 	mdp_bl_scale_cfg,
 	mdp_op_pa_cfg,
+	mdp_op_dither_cfg,
+	mdp_op_gamut_cfg,
 	mdp_op_max,
 };
 
@@ -503,6 +529,8 @@
 		struct mdp_qseed_cfg_data qseed_cfg_data;
 		struct mdp_bl_scale_data bl_scale_data;
 		struct mdp_pa_cfg_data pa_cfg_data;
+		struct mdp_dither_cfg_data dither_cfg_data;
+		struct mdp_gamut_cfg_data gamut_cfg_data;
 	} data;
 };
 
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 647a7ef..03390b1 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -223,9 +223,14 @@
 extern int power_supply_set_supply_type(struct power_supply *psy,
 					enum power_supply_type supply_type);
 extern int power_supply_is_system_supplied(void);
+extern int power_supply_register(struct device *parent,
+				 struct power_supply *psy);
+extern void power_supply_unregister(struct power_supply *psy);
+extern int power_supply_powers(struct power_supply *psy, struct device *dev);
 #else
 static inline struct power_supply *power_supply_get_by_name(char *name)
-							{ return -ENOSYS; }
+							{ return NULL; }
+static inline void power_supply_changed(struct power_supply *psy) { }
 static inline int power_supply_am_i_supplied(struct power_supply *psy)
 							{ return -ENOSYS; }
 static inline int power_supply_set_battery_charged(struct power_supply *psy)
@@ -243,16 +248,18 @@
 							int type)
 							{ return -ENOSYS; }
 static inline int power_supply_set_supply_type(struct power_supply *psy,
-					enum power_supply_type supply_type);
+					enum power_supply_type supply_type)
 							{ return -ENOSYS; }
 static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
+static inline int power_supply_register(struct device *parent,
+					struct power_supply *psy)
+							{ return -ENOSYS; }
+static inline void power_supply_unregister(struct power_supply *psy) { }
+static inline int power_supply_powers(struct power_supply *psy,
+				      struct device *dev)
+							{ return -ENOSYS; }
 #endif
 
-extern int power_supply_register(struct device *parent,
-				 struct power_supply *psy);
-extern void power_supply_unregister(struct power_supply *psy);
-extern int power_supply_powers(struct power_supply *psy, struct device *dev);
-
 /* For APM emulation, think legacy userspace. */
 extern struct class *power_supply_class;
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2c9509d..1f13da3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -142,6 +142,8 @@
 extern unsigned long nr_iowait_cpu(int cpu);
 extern unsigned long this_cpu_load(void);
 
+extern void sched_update_nr_prod(int cpu, unsigned long nr, bool inc);
+extern void sched_get_nr_running_avg(int *avg, int *iowait_avg);
 
 extern void calc_global_load(unsigned long ticks);
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 68a87bf..44c64e8 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -368,6 +368,15 @@
 	struct mon_bus *mon_bus;	/* non-null when associated */
 	int monitored;			/* non-zero when monitored */
 #endif
+	unsigned skip_resume:1;		/* All USB devices are brought into full
+					 * power state after system resume. It
+					 * is desirable for some buses to keep
+					 * their devices in suspend state even
+					 * after system resume. The devices
+					 * are resumed later when a remote
+					 * wakeup is detected or an interface
+					 * driver starts I/O.
+					 */
 };
 
 /* ----------------------------------------------------------------------- */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 8e6550f..920cf77 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -294,6 +294,8 @@
  * @xo_handle: TCXO buffer handle
  * @bus_perf_client: Bus performance client handle to request BUS bandwidth
  * @mhl_enabled: MHL driver registration successful and MHL enabled.
+ * @chg_check_timer: The timer used to implement the workaround to detect
+ *               very slow plug in of wall charger.
  */
 struct msm_otg {
 	struct usb_phy phy;
@@ -323,6 +325,7 @@
 #define A_CONN		15
 #define B_BUS_REQ	16
 #define MHL	        17
+#define B_FALSE_SDP	18
 	unsigned long inputs;
 	struct work_struct sm_work;
 	bool sm_work_pending;
@@ -345,6 +348,7 @@
 	struct msm_xo_voter *xo_handle;
 	uint32_t bus_perf_client;
 	bool mhl_enabled;
+	struct timer_list chg_check_timer;
 	/*
 	 * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
 	 * analog regulators while going to low power mode.
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b265eb9..07beb50 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1798,6 +1798,12 @@
 	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 22)
+enum v4l2_mpeg_vidc_video_h264_au_delimiter {
+	V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1
+};
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index d32bc57..7a194ca 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -58,6 +58,7 @@
 int wcnss_hardware_type(void);
 void *wcnss_prealloc_get(unsigned int size);
 int wcnss_prealloc_put(void *ptr);
+void wcnss_reset_intr(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 484d08f..180b38d 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -55,6 +55,7 @@
 #define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
 #define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
 #define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
+#define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -373,4 +374,8 @@
 	u32 sps_pps_for_idr_enable_flag;
 };
 
+struct vcd_property_avc_delimiter_enable {
+	u32 avc_delimiter_enable_flag;
+};
+
 #endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index ed9af2c..6658b8c 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -34,6 +34,8 @@
 
 #define MSM_CAM_IOCTL_MAGIC 'm'
 
+#define MAX_SERVER_PAYLOAD_LENGTH 8192
+
 #define MSM_CAM_IOCTL_GET_SENSOR_INFO \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *)
 
@@ -862,7 +864,10 @@
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
 #define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17)
-#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
+#define MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+19)
+
 
 #define MSM_V4L2_PID_MOTION_ISO              V4L2_CID_PRIVATE_BASE
 #define MSM_V4L2_PID_EFFECT                 (V4L2_CID_PRIVATE_BASE+1)
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index d7b1340..1cccb2b 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -104,6 +104,7 @@
 #define MARIMBA_2_1	0x02010204
 #define BAHAMA_1_0	0x0302010A
 #define BAHAMA_2_0	0x04020205
+#define BAHAMA_2_1      0x04020309
 #define WAIT_TIMEOUT 2000
 #define RADIO_INIT_TIME 15
 #define TAVARUA_DELAY 10
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 2641720..3b1bd7c2 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -13,6 +13,7 @@
 
 #ifndef VCAP_FMT_H
 #define VCAP_FMT_H
+#include <linux/videodev2.h>
 
 #define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE)
 
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1da6aa2..d902881 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1890,6 +1890,7 @@
 	struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
 	struct afe_param_id_slimbus_cfg           slim_sch;
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
+	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
 } __packed;
 
 struct afe_audioif_config_command {
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 31d684b..54af7d6a 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -86,6 +86,7 @@
 #define SND_AUDIOCODEC_DTS_PASS_THROUGH      ((__u32) 0x00000012)
 #define SND_AUDIOCODEC_DTS_LBR               ((__u32) 0x00000013)
 #define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
+#define SND_AUDIOCODEC_PASS_THROUGH          ((__u32) 0x00000015)
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
@@ -331,6 +332,10 @@
 	__u32 bw;	/* encoder bandwidth */
 	__s32 reserved[15];
 };
+struct snd_dec_dts {
+	__u32 modelIdLength;
+	__u8 *modelId;
+};
 
 union snd_codec_options {
 	struct snd_enc_wma wma;
@@ -338,6 +343,7 @@
 	struct snd_enc_real real;
 	struct snd_enc_flac flac;
 	struct snd_enc_generic generic;
+	struct snd_dec_dts dts;
 };
 
 /** struct snd_codec_desc - description of codec capabilities
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 8ccc9f4..e107130 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -13,6 +13,8 @@
 #define __Q6AFE_V2_H__
 #include <sound/apr_audio-v2.h>
 
+#define IN			0x000
+#define OUT			0x001
 #define MSM_AFE_MONO        0
 #define MSM_AFE_MONO_RIGHT  1
 #define MSM_AFE_MONO_LEFT   2
@@ -71,6 +73,40 @@
 	AFE_MAX_PORTS
 };
 
+struct afe_audio_buffer {
+	dma_addr_t phys;
+	void       *data;
+	uint32_t   used;
+	uint32_t   size;/* size of buffer */
+	uint32_t   actual_size; /* actual number of bytes read by DSP */
+	struct      ion_handle *handle;
+	struct      ion_client *client;
+};
+
+struct afe_audio_port_data {
+	struct afe_audio_buffer *buf;
+	uint32_t	    max_buf_cnt;
+	uint32_t	    dsp_buf;
+	uint32_t	    cpu_buf;
+	struct list_head    mem_map_handle;
+	uint32_t	    tmp_hdl;
+	/* read or write locks */
+	struct mutex	    lock;
+	spinlock_t	    dsp_lock;
+};
+
+struct afe_audio_client {
+	atomic_t	       cmd_state;
+	/* Relative or absolute TS */
+	uint32_t	       time_flag;
+	void		       *priv;
+	uint64_t	       time_stamp;
+	struct mutex	       cmd_lock;
+	/* idx:1 out port, 0: in port*/
+	struct afe_audio_port_data port[2];
+	wait_queue_head_t      cmd_wait;
+};
+
 int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
 int afe_close(int port_id);
 int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
@@ -80,6 +116,7 @@
 int afe_get_port_index(u16 port_id);
 int afe_start_pseudo_port(u16 port_id);
 int afe_stop_pseudo_port(u16 port_id);
+uint32_t afe_req_mmap_handle(void);
 int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz);
 int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz);
 int afe_cmd_memory_unmap(u32 dma_addr_p);
@@ -98,6 +135,14 @@
 int afe_apply_gain(u16 port_id, u16 gain);
 int afe_q6_interface_prepare(void);
 int afe_get_port_type(u16 port_id);
+int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir,
+			struct afe_audio_client *ac,
+			unsigned int bufsz,
+			unsigned int bufcnt);
+struct afe_audio_client *q6afe_audio_client_alloc(void *priv);
+int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
+			struct afe_audio_client *ac);
+void q6afe_audio_client_free(struct afe_audio_client *ac);
 /* if port_id is virtual, convert to physical..
  * if port_id is already physical, return physical
  */
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 5f4a7be..9cc0de4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -49,6 +49,7 @@
 #define FORMAT_MAT	0x0017
 #define FORMAT_AAC	0x0018
 #define FORMAT_DTS_LBR 0x0019
+#define FORMAT_PASS_THROUGH 0x0020
 
 #define ENCDEC_SBCBITRATE   0x0001
 #define ENCDEC_IMMEDIATE_DECODE 0x0002
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d0c5baf..4eec66e 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -295,7 +295,9 @@
 static int
 cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-	return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
+	return *rdp->nxttail[RCU_DONE_TAIL +
+			     ACCESS_ONCE(rsp->completed) != rdp->completed] &&
+	       !rcu_gp_in_progress(rsp);
 }
 
 /*
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 9a7dd35..3ede7d9 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -11,7 +11,7 @@
 CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
 endif
 
-obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o
+obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o sched_avg.o
 obj-$(CONFIG_SMP) += cpupri.o
 obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
 obj-$(CONFIG_SCHEDSTATS) += stats.o
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index fb3acba..451bd4f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -916,11 +916,13 @@
 
 static inline void inc_nr_running(struct rq *rq)
 {
+	sched_update_nr_prod(cpu_of(rq), rq->nr_running, true);
 	rq->nr_running++;
 }
 
 static inline void dec_nr_running(struct rq *rq)
 {
+	sched_update_nr_prod(cpu_of(rq), rq->nr_running, false);
 	rq->nr_running--;
 }
 
diff --git a/kernel/sched/sched_avg.c b/kernel/sched/sched_avg.c
new file mode 100644
index 0000000..8eaf2f7
--- /dev/null
+++ b/kernel/sched/sched_avg.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/*
+ * Scheduler hook for average runqueue determination
+ */
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/hrtimer.h>
+#include <linux/sched.h>
+#include <linux/math64.h>
+
+static DEFINE_PER_CPU(u64, nr_prod_sum);
+static DEFINE_PER_CPU(u64, last_time);
+static DEFINE_PER_CPU(u64, nr);
+static DEFINE_PER_CPU(unsigned long, iowait_prod_sum);
+static DEFINE_PER_CPU(spinlock_t, nr_lock) = __SPIN_LOCK_UNLOCKED(nr_lock);
+static s64 last_get_time;
+
+/**
+ * sched_get_nr_running_avg
+ * @return: Average nr_running and iowait value since last poll.
+ *	    Returns the avg * 100 to return up to two decimal points
+ *	    of accuracy.
+ *
+ * Obtains the average nr_running value since the last poll.
+ * This function may not be called concurrently with itself
+ */
+void sched_get_nr_running_avg(int *avg, int *iowait_avg)
+{
+	int cpu;
+	u64 curr_time = sched_clock();
+	u64 diff = curr_time - last_get_time;
+	u64 tmp_avg = 0, tmp_iowait = 0;
+
+	*avg = 0;
+	*iowait_avg = 0;
+
+	if (!diff)
+		return;
+
+	last_get_time = curr_time;
+	/* read and reset nr_running counts */
+	for_each_possible_cpu(cpu) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&per_cpu(nr_lock, cpu), flags);
+		tmp_avg += per_cpu(nr_prod_sum, cpu);
+		tmp_avg += per_cpu(nr, cpu) *
+			(curr_time - per_cpu(last_time, cpu));
+		tmp_iowait = per_cpu(iowait_prod_sum, cpu);
+		tmp_iowait +=  nr_iowait_cpu(cpu) *
+			(curr_time - per_cpu(last_time, cpu));
+		per_cpu(last_time, cpu) = curr_time;
+		per_cpu(nr_prod_sum, cpu) = 0;
+		per_cpu(iowait_prod_sum, cpu) = 0;
+		spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
+	}
+
+	*avg = (int)div64_u64(tmp_avg * 100, diff);
+	*iowait_avg = (int)div64_u64(tmp_iowait * 100, diff);
+
+	BUG_ON(*avg < 0);
+	pr_debug("%s - avg:%d\n", __func__, *avg);
+	BUG_ON(*iowait_avg < 0);
+	pr_debug("%s - avg:%d\n", __func__, *iowait_avg);
+}
+EXPORT_SYMBOL(sched_get_nr_running_avg);
+
+/**
+ * sched_update_nr_prod
+ * @cpu: The core id of the nr running driver.
+ * @nr: Updated nr running value for cpu.
+ * @inc: Whether we are increasing or decreasing the count
+ * @return: N/A
+ *
+ * Update average with latest nr_running value for CPU
+ */
+void sched_update_nr_prod(int cpu, unsigned long nr_running, bool inc)
+{
+	int diff;
+	s64 curr_time;
+	unsigned long flags;
+
+	spin_lock_irqsave(&per_cpu(nr_lock, cpu), flags);
+	curr_time = sched_clock();
+	diff = curr_time - per_cpu(last_time, cpu);
+	per_cpu(last_time, cpu) = curr_time;
+	per_cpu(nr, cpu) = nr_running + (inc ? 1 : -1);
+
+	BUG_ON(per_cpu(nr, cpu) < 0);
+
+	per_cpu(nr_prod_sum, cpu) += nr_running * diff;
+	per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff;
+	spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
+}
+EXPORT_SYMBOL(sched_update_nr_prod);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index a1d2849..5ba1770 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -418,6 +418,19 @@
 
 	  If in doubt, say N.
 
+config CPU_FREQ_SWITCH_PROFILER
+	bool "CPU frequency switch time profiler"
+	select GENERIC_TRACER
+	help
+	  This option enables the CPU frequency switch profiler. A file is
+	  created in debugfs called "cpu_freq_switch_profile_enabled", which
+	  defaults to zero. When a 1 is echoed into this file, profiling begins.
+	  When a zero is echoed, profiling stops. A "cpu_freq_switch" file is
+	  also created in the trace_stats directory; this file shows the
+	  switches that have occurred and duration statistics.
+
+	  If in doubt, say N.
+
 config FTRACE_MCOUNT_RECORD
 	def_bool y
 	depends on DYNAMIC_FTRACE
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 5f39a07..3c13931 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -36,6 +36,7 @@
 obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
 obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
 obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
+obj-$(CONFIG_CPU_FREQ_SWITCH_PROFILER) += trace_cpu_freq_switch.o
 obj-$(CONFIG_NOP_TRACER) += trace_nop.o
 obj-$(CONFIG_STACK_TRACER) += trace_stack.o
 obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
diff --git a/kernel/trace/trace_cpu_freq_switch.c b/kernel/trace/trace_cpu_freq_switch.c
new file mode 100644
index 0000000..7e7b104
--- /dev/null
+++ b/kernel/trace/trace_cpu_freq_switch.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+#include <linux/ktime.h>
+#include <trace/events/power.h>
+#include "trace_stat.h"
+#include "trace.h"
+
+struct trans {
+	struct rb_node node;
+	unsigned int cpu;
+	unsigned int start_freq;
+	unsigned int end_freq;
+	unsigned int min_us;
+	unsigned int max_us;
+	ktime_t total_t;
+	unsigned int count;
+};
+static struct rb_root freq_trans_tree = RB_ROOT;
+
+static struct trans *tr_search(struct rb_root *root, unsigned int cpu,
+			       unsigned int start_freq, unsigned int end_freq)
+{
+	struct rb_node *node = root->rb_node;
+
+	while (node) {
+		struct trans *tr = container_of(node, struct trans, node);
+
+		if (cpu < tr->cpu)
+			node = node->rb_left;
+		else if (cpu > tr->cpu)
+			node = node->rb_right;
+		else if (start_freq < tr->start_freq)
+			node = node->rb_left;
+		else if (start_freq > tr->start_freq)
+			node = node->rb_right;
+		else if (end_freq < tr->end_freq)
+			node = node->rb_left;
+		else if (end_freq > tr->end_freq)
+			node = node->rb_right;
+		else
+			return tr;
+	}
+	return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct trans *tr)
+{
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+	while (*new) {
+		struct trans *this = container_of(*new, struct trans, node);
+
+		parent = *new;
+		if (tr->cpu < this->cpu)
+			new = &((*new)->rb_left);
+		else if (tr->cpu > this->cpu)
+			new = &((*new)->rb_right);
+		else if (tr->start_freq < this->start_freq)
+			new = &((*new)->rb_left);
+		else if (tr->start_freq > this->start_freq)
+			new = &((*new)->rb_right);
+		else if (tr->end_freq < this->end_freq)
+			new = &((*new)->rb_left);
+		else if (tr->end_freq > this->end_freq)
+			new = &((*new)->rb_right);
+		else
+			return -EINVAL;
+	}
+
+	rb_link_node(&tr->node, parent, new);
+	rb_insert_color(&tr->node, root);
+
+	return 0;
+}
+
+struct trans_state {
+	spinlock_t lock;
+	unsigned int start_freq;
+	unsigned int end_freq;
+	ktime_t start_t;
+	bool started;
+};
+static DEFINE_PER_CPU(struct trans_state, freq_trans_state);
+
+static DEFINE_SPINLOCK(state_lock);
+
+static void probe_start(void *ignore, unsigned int start_freq,
+			unsigned int end_freq, unsigned int cpu)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	per_cpu(freq_trans_state, cpu).start_freq = start_freq;
+	per_cpu(freq_trans_state, cpu).end_freq = end_freq;
+	per_cpu(freq_trans_state, cpu).start_t = ktime_get();
+	per_cpu(freq_trans_state, cpu).started = true;
+	spin_unlock_irqrestore(&state_lock, flags);
+}
+
+static void probe_end(void *ignore, unsigned int cpu)
+{
+	unsigned long flags;
+	struct trans *tr;
+	s64 dur_us;
+	ktime_t dur_t, end_t = ktime_get();
+
+	spin_lock_irqsave(&state_lock, flags);
+
+	if (!per_cpu(freq_trans_state, cpu).started)
+		goto out;
+
+	dur_t = ktime_sub(end_t, per_cpu(freq_trans_state, cpu).start_t);
+	dur_us = ktime_to_us(dur_t);
+
+	tr = tr_search(&freq_trans_tree, cpu,
+		       per_cpu(freq_trans_state, cpu).start_freq,
+		       per_cpu(freq_trans_state, cpu).end_freq);
+	if (!tr) {
+		tr = kzalloc(sizeof(*tr), GFP_ATOMIC);
+		if (!tr) {
+			WARN_ONCE(1, "CPU frequency trace is now invalid!\n");
+			goto out;
+		}
+
+		tr->start_freq = per_cpu(freq_trans_state, cpu).start_freq;
+		tr->end_freq = per_cpu(freq_trans_state, cpu).end_freq;
+		tr->cpu = cpu;
+		tr->min_us = UINT_MAX;
+		tr_insert(&freq_trans_tree, tr);
+	}
+	tr->total_t = ktime_add(tr->total_t, dur_t);
+	tr->count++;
+
+	if (dur_us > tr->max_us)
+		tr->max_us = dur_us;
+	if (dur_us < tr->min_us)
+		tr->min_us = dur_us;
+
+	per_cpu(freq_trans_state, cpu).started = false;
+out:
+	spin_unlock_irqrestore(&state_lock, flags);
+}
+
+static void *freq_switch_stat_start(struct tracer_stat *trace)
+{
+	struct rb_node *n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	n = rb_first(&freq_trans_tree);
+	spin_unlock_irqrestore(&state_lock, flags);
+
+	return n;
+}
+
+static void *freq_switch_stat_next(void *prev, int idx)
+{
+	struct rb_node *n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	n = rb_next(prev);
+	spin_unlock_irqrestore(&state_lock, flags);
+
+	return n;
+}
+
+static int freq_switch_stat_show(struct seq_file *s, void *p)
+{
+	unsigned long flags;
+	struct trans *tr = p;
+
+	spin_lock_irqsave(&state_lock, flags);
+	seq_printf(s, "%3d %9d %8d %5d %6lld %6d %6d\n", tr->cpu,
+		   tr->start_freq, tr->end_freq, tr->count,
+		   div_s64(ktime_to_us(tr->total_t), tr->count),
+		   tr->min_us, tr->max_us);
+	spin_unlock_irqrestore(&state_lock, flags);
+
+	return 0;
+}
+
+static void freq_switch_stat_release(void *stat)
+{
+	struct trans *tr = stat;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state_lock, flags);
+	rb_erase(&tr->node, &freq_trans_tree);
+	spin_unlock_irqrestore(&state_lock, flags);
+	kfree(tr);
+}
+
+static int freq_switch_stat_headers(struct seq_file *s)
+{
+	seq_printf(s, "CPU START_KHZ  END_KHZ COUNT AVG_US MIN_US MAX_US\n");
+	seq_printf(s, "  |         |        |     |      |      |      |\n");
+	return 0;
+}
+
+struct tracer_stat freq_switch_stats __read_mostly = {
+	.name = "cpu_freq_switch",
+	.stat_start = freq_switch_stat_start,
+	.stat_next = freq_switch_stat_next,
+	.stat_show = freq_switch_stat_show,
+	.stat_release = freq_switch_stat_release,
+	.stat_headers = freq_switch_stat_headers
+};
+
+static void trace_freq_switch_disable(void)
+{
+	unregister_stat_tracer(&freq_switch_stats);
+	unregister_trace_cpu_frequency_switch_end(probe_end, NULL);
+	unregister_trace_cpu_frequency_switch_start(probe_start, NULL);
+	pr_info("disabled cpu frequency switch time profiling\n");
+}
+
+static int trace_freq_switch_enable(void)
+{
+	int ret;
+
+	ret = register_trace_cpu_frequency_switch_start(probe_start, NULL);
+	if (ret)
+		goto out;
+
+	ret = register_trace_cpu_frequency_switch_end(probe_end, NULL);
+	if (ret)
+		goto err_register_switch_end;
+
+	ret = register_stat_tracer(&freq_switch_stats);
+	if (ret)
+		goto err_register_stat_tracer;
+
+	pr_info("enabled cpu frequency switch time profiling\n");
+	return 0;
+
+err_register_stat_tracer:
+	unregister_trace_cpu_frequency_switch_end(probe_end, NULL);
+err_register_switch_end:
+	register_trace_cpu_frequency_switch_start(probe_start, NULL);
+out:
+	pr_err("failed to enable cpu frequency switch time profiling\n");
+
+	return ret;
+}
+
+static DEFINE_MUTEX(debugfs_lock);
+static bool trace_freq_switch_enabled;
+
+static int debug_toggle_tracing(void *data, u64 val)
+{
+	int ret = 0;
+
+	mutex_lock(&debugfs_lock);
+
+	if (val == 1 && !trace_freq_switch_enabled)
+		ret = trace_freq_switch_enable();
+	else if (val == 0 && trace_freq_switch_enabled)
+		trace_freq_switch_disable();
+	else if (val > 1)
+		ret = -EINVAL;
+
+	if (!ret)
+		trace_freq_switch_enabled = val;
+
+	mutex_unlock(&debugfs_lock);
+
+	return ret;
+}
+
+static int debug_tracing_state_get(void *data, u64 *val)
+{
+	mutex_lock(&debugfs_lock);
+	*val = trace_freq_switch_enabled;
+	mutex_unlock(&debugfs_lock);
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debug_tracing_state_fops, debug_tracing_state_get,
+			debug_toggle_tracing, "%llu\n");
+
+static int __init trace_freq_switch_init(void)
+{
+	struct dentry *d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return 0;
+
+	debugfs_create_file("cpu_freq_switch_profile_enabled",
+		S_IRUGO | S_IWUSR, d_tracer, NULL, &debug_tracing_state_fops);
+
+	return 0;
+}
+late_initcall(trace_freq_switch_init);
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 9432a06..b303878 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -4976,6 +4976,7 @@
 	SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
 
 	SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
+	SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x5B),
 
 };
 
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index a47e446..deddbe8 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -6526,7 +6526,7 @@
 	s16 mb_v[num_det];
 	s32 mic_mv[num_det];
 	bool inval;
-	bool highdelta;
+	bool highdelta = false;
 	bool ahighv = false, highv;
 	bool gndmicswapped = false;
 
@@ -6587,26 +6587,29 @@
 			if (vddioswitch)
 				__tabla_codec_switch_micbias(tabla->codec, 0,
 							     false, false);
-			/* claim UNSUPPORTED plug insertion when
-			 * good headset is detected but HPHR GND switch makes
-			 * delta difference */
-			if (i == (num_det - 2) && highdelta && !ahighv)
-				gndmicswapped = true;
-			else if (i == (num_det - 1) && inval) {
-				if (gndmicswapped)
-					plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
-				else
-					plug_type[0] = PLUG_TYPE_INVALID;
-			}
 		}
 		pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
 			 "VDDIO %d, inval %d\n", __func__,
 			 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
 			 vddioswitch, inval);
 		/* don't need to run further DCEs */
-		if (ahighv && inval)
+		if ((ahighv || !vddioswitch) && inval)
 			break;
 		mic_mv[i] = scaled;
+
+		/*
+		 * claim UNSUPPORTED plug insertion when
+		 * good headset is detected but HPHR GND switch makes
+		 * delta difference
+		 */
+		if (i == (num_det - 2) && highdelta && !ahighv)
+			gndmicswapped = true;
+		else if (i == (num_det - 1) && inval) {
+			if (gndmicswapped)
+				plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
+			else
+				plug_type[0] = PLUG_TYPE_INVALID;
+		}
 	}
 
 	for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
index 68a4670..c49c276 100644
--- a/sound/soc/codecs/wcd9320-tables.c
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -673,7 +673,7 @@
 	[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
 };
 
-const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE] = {
+const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE] = {
 	[TAIKO_A_CHIP_CTL] = TAIKO_A_CHIP_CTL__POR,
 	[TAIKO_A_CHIP_STATUS] = TAIKO_A_CHIP_STATUS__POR,
 	[TAIKO_A_CHIP_ID_BYTE_0] = TAIKO_A_CHIP_ID_BYTE_0__POR,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 136024c..e8bb652 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -685,7 +685,7 @@
 				u32 compander, u32 enable, int event)
 {
 	int value = 0;
-	int mask = 1 << 4;
+	int mask = 1 << 5;
 	int gain = 0;
 	int gain_offset;
 	if (compander >= COMPANDER_MAX) {
@@ -828,19 +828,23 @@
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Halt the compander*/
-		snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
-			w->shift * 8, 1 << 2, 1 << 2);
+		if (taiko->comp_enabled[w->shift] != 0) {
+			snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+				w->shift * 8, 1 << 2, 1 << 2);
+		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Restore the gain */
-		taiko_config_gain_compander(codec, w->shift,
-				taiko->comp_enabled[w->shift], event);
-		/* Disable the compander*/
-		snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
-			w->shift * 8, 0x03, 0x00);
-		/* Turn off the clock for compander in pair*/
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
-			0x03 << comp_shift[w->shift], 0);
+		if (taiko->comp_enabled[w->shift] != 0) {
+			taiko_config_gain_compander(codec, w->shift,
+					taiko->comp_enabled[w->shift], event);
+			/* Disable the compander*/
+			snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+					w->shift * 8, 0x03, 0x00);
+			/* Turn off the clock for compander in pair*/
+			snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
+				0x03 << comp_shift[w->shift], 0);
+		}
 		break;
 	}
 	return 0;
@@ -1716,7 +1720,7 @@
 		usleep_range(100, 100);
 		taiko_codec_enable_audio_mode_bandgap(codec);
 	} else if (choice == TAIKO_BANDGAP_OFF) {
-		snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x50);
 	} else {
 		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
 	}
@@ -1730,7 +1734,7 @@
 	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x04, 0x00);
 	usleep_range(50, 50);
 	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x02, 0x02);
-	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x05, 0x00);
+	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x00);
 	usleep_range(50, 50);
 	taiko->clock_active = false;
 }
@@ -1815,10 +1819,9 @@
 		/* switch to MCLK */
 		snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x08, 0x00);
 
-		if (taiko->mbhc_polling_active) {
+		if (taiko->mbhc_polling_active)
 			snd_soc_write(codec, TAIKO_A_CLK_BUFF_EN2, 0x02);
-			taiko_codec_enable_config_mode(codec, 0);
-		}
+		taiko_codec_enable_config_mode(codec, 0);
 	}
 
 	snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x01);
@@ -2658,7 +2661,7 @@
 	return ret;
 }
 
-static int taiko_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+static int taiko_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
@@ -4295,25 +4298,25 @@
 			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX6 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 	SND_SOC_DAPM_MIXER_E("RX7 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
-		0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -4321,11 +4324,11 @@
 	SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 	SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
-		&rx4_dsm_mux, taiko_codec_reset_interpolator,
+		&rx4_dsm_mux, taiko_codec_enable_interpolator,
 		SND_SOC_DAPM_PRE_PMU),
 
 	SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0,
-		&rx6_dsm_mux, taiko_codec_reset_interpolator,
+		&rx6_dsm_mux, taiko_codec_enable_interpolator,
 		SND_SOC_DAPM_PRE_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
@@ -4381,10 +4384,10 @@
 	SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
 		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
+	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
 		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
+	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
 		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
@@ -7088,7 +7091,7 @@
 	return rc;
 }
 
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
 
 	/* set MCLk to 9.6 */
 	TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x0A),
@@ -7096,14 +7099,10 @@
 
 	/* EAR PA deafults  */
 	TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
-	/* HPH PA */
-	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 
 	/** BUCK and NCP defaults for EAR and HS */
 	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
 	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
-	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
 
 	/* CLASS-H defaults for EAR and HS */
 	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
@@ -7120,7 +7119,6 @@
 	 */
 	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
 
-
 	/* RX deafults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -7142,20 +7140,50 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
 };
 
+static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+	/*
+	 * The following only need to be written for Taiko 1.0 parts.
+	 * Taiko 2.0 will have appropriate defaults for these registers.
+	 */
+	/* Choose max non-overlap time for NCP */
+	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
+	/* Use 25mV/50mV for deltap/m to reduce ripple */
+	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+	/*
+	 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
+	 * Note that the other bits of this register will be changed during
+	 * Rx PA bring up.
+	 */
+	TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+	/* Reduce HPH DAC bias to 70% */
+	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
+	/*Reduce EAR DAC bias to 70% */
+	TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0x76),
+	/* Reduce LINE DAC bias to 70% */
+	TAIKO_REG_VAL(TAIKO_A_RX_LINE_BIAS_PA, 0x78),
+};
+
 static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
 {
 	u32 i;
+	struct wcd9xxx *taiko_core = dev_get_drvdata(codec->dev->parent);
 
-	for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
-		snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
+	for (i = 0; i < ARRAY_SIZE(taiko_reg_defaults); i++)
+		snd_soc_write(codec, taiko_reg_defaults[i].reg,
+				taiko_reg_defaults[i].val);
+
+	if (TAIKO_IS_1_0(taiko_core->version)) {
+		for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
+			snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
 				taiko_1_0_reg_defaults[i].val);
+	}
 }
 
 static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
 	/* Initialize current threshold to 350MA
 	 * number of wait and run cycles to 4096
 	 */
-	{TAIKO_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
+	{TAIKO_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
 	{TAIKO_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
 
 	/* Initialize gain registers to use register gain */
@@ -7185,7 +7213,7 @@
 
 	/* Use 16 bit sample size for RX */
 	{TAIKO_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
-	{TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
+	{TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
 
 	/*enable HPF filter for TX paths */
 	{TAIKO_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
@@ -7601,7 +7629,7 @@
 	.volatile_register = taiko_volatile,
 
 	.reg_cache_size = TAIKO_CACHE_SIZE,
-	.reg_cache_default = taiko_reg_defaults,
+	.reg_cache_default = taiko_reset_reg_defaults,
 	.reg_word_size = 1,
 
 	.controls = taiko_snd_controls,
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 739ab17..7ca8ff0 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -36,7 +36,7 @@
 				SND_JACK_BTN_6 | SND_JACK_BTN_7)
 
 extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
-extern const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE];
+extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
 
 enum taiko_micbias_num {
 	TAIKO_MICBIAS1 = 0,
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
index f57d686..e309370 100644
--- a/sound/soc/msm/apq8064-i2s.c
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -63,9 +63,8 @@
 
 #define JACK_DETECT_GPIO 38
 
-#define APQ_I2S_SLAVE_CONFIG	0
 /* MCLK selection GPIOs from PMIC */
-#define PM_GPIO_MCLK_MDM	10
+#define PM_GPIO_MCLK_MDM	27
 #define PM_GPIO_MCLK_APQ	41
 
 /* SPKR I2S Configuration */
@@ -170,10 +169,8 @@
 };
 
 
-#if APQ_I2S_SLAVE_CONFIG
 static u32 mdm_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_MDM);
 static u32 apq_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_APQ);
-#endif
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
 static int msm_spk_control;
@@ -186,9 +183,6 @@
 static struct clk *i2s_rx_bit_clk;
 static struct clk *i2s_tx_bit_clk;
 
-#if (!APQ_I2S_SLAVE_CONFIG)
-static struct clk *mi2s_osr_clk;
-#endif
 static struct clk *mi2s_bit_clk;
 
 static int msm_i2s_rx_ch = 1;
@@ -953,14 +947,10 @@
 static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
+	pr_debug("%s(): channels = %d\n", __func__, msm_mi2s_rx_ch);
 	channels->min = channels->max = msm_mi2s_rx_ch;
 
 	return 0;
@@ -969,15 +959,10 @@
 static int msm_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
-
+	pr_debug("%s(): channels = %d\n", __func__, msm_mi2s_tx_ch);
 	channels->min = channels->max = msm_mi2s_tx_ch;
 
 	return 0;
@@ -987,14 +972,10 @@
 static int msm_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
+	pr_debug("%s(): channels = %d\n", __func__, msm_i2s_rx_ch);
 	channels->min = channels->max = msm_i2s_rx_ch;
 
 	return 0;
@@ -1003,15 +984,10 @@
 static int msm_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
-	struct snd_interval *rate = hw_param_interval(params,
-	SNDRV_PCM_HW_PARAM_RATE);
-
 	struct snd_interval *channels = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	pr_debug("%s()\n", __func__);
-	rate->min = rate->max = 48000;
-
+	pr_debug("%s(): channels = %d\n", __func__, msm_i2s_tx_ch);
 	channels->min = channels->max = msm_i2s_tx_ch;
 
 	return 0;
@@ -1038,7 +1014,6 @@
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-#if APQ_I2S_SLAVE_CONFIG
 	struct pm_gpio param = {
 		.direction      = PM_GPIO_DIR_OUT,
 		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
@@ -1048,14 +1023,13 @@
 		.out_strength   = PM_GPIO_STRENGTH_MED,
 		.function       = PM_GPIO_FUNC_NORMAL,
 	};
-#endif
+
 	pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
 	ret = gpio_request(GPIO_MI2S_MCLK, "MI2S_MCLK");
 	if (ret)
 		pr_err("%s: Failed to request gpio %d\n", __func__,
 			   GPIO_MI2S_MCLK);
 
-#if APQ_I2S_SLAVE_CONFIG
 	/* APQ provides the mclk to codec */
 	ret = gpio_request(mdm_mclk_gpio, "MDM_MCLK_SWITCH");
 	if (ret) {
@@ -1070,6 +1044,7 @@
 	else
 		gpio_direction_output(mdm_mclk_gpio, 0);
 
+	pr_debug("%s: Config mdm_mclk_gpio\n", __func__);
 	ret = gpio_request(apq_mclk_gpio, "APQ_MCLK_SWITCH");
 	if (ret) {
 		pr_err("%s: Failed to request gpio %d\n", __func__,
@@ -1082,12 +1057,9 @@
 			apq_mclk_gpio);
 	else
 		gpio_direction_output(apq_mclk_gpio, 1);
-	pr_debug("%s: Config mdm_mclk_gpio and apq_mclk_gpio\n",
-	__func__);
-#else
-	pr_debug("%s: Not config mdm_mclk_gpio and apq_mclk_gpio\n",
-	__func__);
-#endif
+
+	pr_debug("%s: Config apq_mclk_gpio\n", __func__);
+
 	snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
 				ARRAY_SIZE(apq8064_dapm_widgets));
 
@@ -1172,12 +1144,10 @@
 
 	ret = tabla_hs_detect(codec, &mbhc_cfg);
 
-#if APQ_I2S_SLAVE_CONFIG
 	/* MDM provides the mclk to codec */
 	gpio_direction_output(apq_mclk_gpio, 0);
 	gpio_direction_output(mdm_mclk_gpio, 1);
-	pr_debug("%s: Should not running here if no clock switch\n", __func__);
-#endif
+	pr_debug("%s: Clock switch to MDM\n", __func__);
 	/* Should we add code to put back codec clock?*/
 	gpio_free(GPIO_MI2S_MCLK);
 	pr_debug("%s: Free MCLK GPIO\n", __func__);
@@ -1202,13 +1172,6 @@
 			clk_put(mi2s_bit_clk);
 			mi2s_bit_clk = NULL;
 		}
-#if (!APQ_I2S_SLAVE_CONFIG)
-		if (mi2s_osr_clk) {
-			clk_disable_unprepare(mi2s_osr_clk);
-			clk_put(mi2s_osr_clk);
-			mi2s_osr_clk = NULL;
-		}
-#endif
 		msm_mi2s_free_gpios();
 	}
 }
@@ -1250,8 +1213,6 @@
 	if (atomic_inc_return(&mi2s_rsc_ref) == 1) {
 		pr_debug("%s: acquire mi2s resources\n", __func__);
 		msm_configure_mi2s_gpio();
-
-#if APQ_I2S_SLAVE_CONFIG
 		pr_debug("%s: APQ is MI2S slave\n", __func__);
 		mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
 		if (IS_ERR(mi2s_bit_clk))
@@ -1266,38 +1227,6 @@
 		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
 		if (IS_ERR_VALUE(ret))
 			pr_err("set format for CPU dai failed\n");
-#else
-		pr_debug("%s: APQ is MI2S master\n", __func__);
-		mi2s_osr_clk = clk_get(cpu_dai->dev, "osr_clk");
-		if (IS_ERR(mi2s_osr_clk))
-			return PTR_ERR(mi2s_osr_clk);
-		clk_set_rate(mi2s_osr_clk, TABLA_EXT_CLK_RATE);
-		ret = clk_prepare_enable(mi2s_osr_clk);
-		if (IS_ERR_VALUE(ret)) {
-			pr_err("Unable to enable mi2s_osr_clk\n");
-			clk_put(mi2s_osr_clk);
-			return ret;
-		}
-		mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
-		if (IS_ERR(mi2s_bit_clk)) {
-			pr_err("Unable to get mi2s_bit_clk\n");
-			clk_disable_unprepare(mi2s_osr_clk);
-			clk_put(mi2s_osr_clk);
-			return PTR_ERR(mi2s_bit_clk);
-		}
-		clk_set_rate(mi2s_bit_clk, 8);
-		ret = clk_prepare_enable(mi2s_bit_clk);
-		if (IS_ERR_VALUE(ret)) {
-			pr_err("Unable to enable mi2s_bit_clk\n");
-			clk_disable_unprepare(mi2s_osr_clk);
-			clk_put(mi2s_osr_clk);
-			clk_put(mi2s_bit_clk);
-			return ret;
-		}
-		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
-		if (IS_ERR_VALUE(ret))
-			pr_err("set format for CPU dai failed\n");
-#endif
 	}
 
 	return ret;
@@ -2028,57 +1957,11 @@
 
 static int msm_aux_pcm_get_gpios(void)
 {
-	int ret = 0;
-
-	pr_debug("%s\n", __func__);
-
-	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
-				__func__, GPIO_AUX_PCM_DOUT);
-		goto fail_dout;
-	}
-
-	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
-				__func__, GPIO_AUX_PCM_DIN);
-		goto fail_din;
-	}
-
-	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
-				__func__, GPIO_AUX_PCM_SYNC);
-		goto fail_sync;
-	}
-	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
-	if (ret < 0) {
-		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
-				__func__, GPIO_AUX_PCM_CLK);
-		goto fail_clk;
-	}
-
 	return 0;
-
-fail_clk:
-	gpio_free(GPIO_AUX_PCM_SYNC);
-fail_sync:
-	gpio_free(GPIO_AUX_PCM_DIN);
-fail_din:
-	gpio_free(GPIO_AUX_PCM_DOUT);
-fail_dout:
-
-	return ret;
 }
 
 static int msm_aux_pcm_free_gpios(void)
 {
-	gpio_free(GPIO_AUX_PCM_DIN);
-	gpio_free(GPIO_AUX_PCM_DOUT);
-	gpio_free(GPIO_AUX_PCM_SYNC);
-	gpio_free(GPIO_AUX_PCM_CLK);
-
 	return 0;
 }
 static int msm_startup(struct snd_pcm_substream *substream)
@@ -2446,6 +2329,14 @@
 static struct snd_soc_dai_link msm_dai[] = {
 	/* FrontEnd DAI Links */
 	{
+		/*
+		 * In APQ8064 I2S platform, there is no playback support
+		 * only voice call is supported so there is no even system
+		 * tone or dialing tone which is by design because I2S clock
+		 * is provided by MDM which matches voice call sample rate
+		 * 8kHz or 16kHz while system tone is 48kHz. We disable the
+		 * playback by feeding the audio to AUX PCM port.
+		 */
 		.name = "MSM8960 Media1",
 		.stream_name = "MultiMedia1",
 		.cpu_dai_name	= "MultiMedia1",
@@ -2799,7 +2690,8 @@
 
 static void __exit msm_audio_exit(void)
 {
-	if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+	if (!(cpu_is_apq8064() || cpu_is_apq8064ab()) ||
+				 (socinfo_get_id() == 130)) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return ;
 	}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index c8cf681..7894368 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -1353,6 +1353,8 @@
 	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
 			channels->min, channels->max);
 
+	if (channels->max < 2)
+		channels->min = channels->max = 2;
 	rate->min = rate->max = 48000;
 
 	return 0;
@@ -2101,7 +2103,8 @@
 {
 	int ret;
 	u32	version = socinfo_get_platform_version();
-	if (!cpu_is_apq8064() || (socinfo_get_id() == 130) ||
+	if (!(cpu_is_apq8064() || cpu_is_apq8064ab()) ||
+		(socinfo_get_id() == 130) ||
 		(machine_is_apq8064_mtp() &&
 		(SOCINFO_VERSION_MINOR(version) == 1))) {
 		pr_info("%s: Not APQ8064 in SLIMBUS mode\n", __func__);
@@ -2141,7 +2144,8 @@
 
 static void __exit msm_audio_exit(void)
 {
-	if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+	if (!(cpu_is_apq8064() || cpu_is_apq8064ab()) ||
+				 (socinfo_get_id() == 130)) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return ;
 	}
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 957b656..011b798 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -45,6 +45,11 @@
 #define TOP_SPK_AMP_POS		0x4
 #define TOP_SPK_AMP_NEG		0x8
 
+#define GPIO_AUX_PCM_DOUT 43
+#define GPIO_AUX_PCM_DIN  44
+#define GPIO_AUX_PCM_SYNC 45
+#define GPIO_AUX_PCM_CLK  46
+
 #define TABLA_EXT_CLK_RATE 12288000
 
 #define TABLA_MBHC_DEF_BUTTONS 8
@@ -942,6 +947,78 @@
 	return ret;
 }
 
+static int mpq8064_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* PCM only supports mono output with 8khz sample rate */
+	rate->min = rate->max = 8000;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+
+static int mpq8064_aux_pcm_get_gpios(void)
+{
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+				__func__, GPIO_AUX_PCM_DOUT);
+		goto fail_dout;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+				__func__, GPIO_AUX_PCM_DIN);
+		goto fail_din;
+	}
+
+	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+				__func__, GPIO_AUX_PCM_SYNC);
+		goto fail_sync;
+	}
+	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+	if (ret < 0) {
+		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+				__func__, GPIO_AUX_PCM_CLK);
+		goto fail_clk;
+	}
+
+	return 0;
+
+fail_clk:
+	gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+	gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+	gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+	return ret;
+}
+
+static int mpq8064_aux_pcm_free_gpios(void)
+{
+	gpio_free(GPIO_AUX_PCM_DIN);
+	gpio_free(GPIO_AUX_PCM_DOUT);
+	gpio_free(GPIO_AUX_PCM_SYNC);
+	gpio_free(GPIO_AUX_PCM_CLK);
+
+	return 0;
+}
+
 static int msm_startup(struct snd_pcm_substream *substream)
 {
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
@@ -955,12 +1032,39 @@
 		 substream->name, substream->stream);
 }
 
+static int mpq8064_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	ret = mpq8064_aux_pcm_get_gpios();
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void mpq8064_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+	pr_debug("%s(): substream = %s\n", __func__, substream->name);
+	mpq8064_aux_pcm_free_gpios();
+}
+
+
 static struct snd_soc_ops msm_be_ops = {
 	.startup = msm_startup,
 	.hw_params = msm_hw_params,
 	.shutdown = msm_shutdown,
 };
 
+static struct snd_soc_ops mpq8064_auxpcm_be_ops = {
+	.startup = mpq8064_auxpcm_startup,
+	.shutdown = mpq8064_auxpcm_shutdown,
+};
+
+
 static int mpq8064_sec_i2s_rx_free_gpios(void)
 {
 	int	i;
@@ -1341,6 +1445,20 @@
 		.ignore_pmdown_time = 1, /* this dailink has playback support */
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
 	},
+	{
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name	= "AUXPCM_HOSTLESS",
+		.platform_name	= "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* dainlink has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1451,6 +1569,31 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
 	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.2",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+		.be_hw_params_fixup = mpq8064_auxpcm_be_params_fixup,
+		.ops = &mpq8064_auxpcm_be_ops,
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.3",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = mpq8064_auxpcm_be_params_fixup,
+	},
 };
 
 
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 78b3abc..0b9d54f 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
 #include <sound/timer.h>
+#include <mach/qdsp6v2/q6core.h>
 
 #include "msm-compr-q6.h"
 #include "msm-pcm-routing.h"
@@ -332,6 +333,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct compr_audio *compr = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct asm_aac_cfg aac_cfg;
 	struct asm_wma_cfg wma_cfg;
@@ -373,11 +375,14 @@
 			pr_err("%s: CMD Format block failed\n", __func__);
 		break;
 	case SND_AUDIOCODEC_AC3_PASS_THROUGH:
-		pr_debug("compressd playback, no need to send"
-			" the decoder params\n");
-		break;
 	case SND_AUDIOCODEC_DTS_PASS_THROUGH:
-		pr_debug("compressd DTS playback,dont send the decoder params\n");
+		pr_debug("compressd playback, no need to send decoder params");
+		pr_debug("decoder id: %d\n",
+			compr->info.codec_param.codec.id);
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					1);
 		break;
 	case SND_AUDIOCODEC_WMA:
 		pr_debug("SND_AUDIOCODEC_WMA\n");
@@ -470,6 +475,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct compr_audio *compr = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
 	struct snd_codec *codec = &compr->info.codec_param.codec;
@@ -499,6 +505,13 @@
 			pr_err("%s: CMD Format block" \
 				"failed: %d\n", __func__, ret);
 		break;
+	case SND_AUDIOCODEC_PCM:
+		pr_debug("SND_AUDIOCODEC_PCM\n");
+		ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+			 prtd->samp_rate, prtd->channel_mode);
+		if (ret < 0)
+			pr_info("%s: CMD Format block failed\n", __func__);
+		break;
 	default:
 		pr_debug("No config for codec %d\n", codec->id);
 	}
@@ -511,6 +524,7 @@
 		read_param.uid = i;
 		switch (codec->id) {
 		case SND_AUDIOCODEC_AMRWB:
+		case SND_AUDIOCODEC_PCM:
 			read_param.len = prtd->pcm_count
 					- COMPRE_CAPTURE_HEADER_SIZE;
 			read_param.paddr = (unsigned long)(buf[i].phys)
@@ -521,17 +535,28 @@
 					buf[i].data);
 			q6asm_async_read(prtd->audio_client, &read_param);
 			break;
-		default:
+		case SND_AUDIOCODEC_PASS_THROUGH:
 			read_param.paddr = (unsigned long)(buf[i].phys);
 			q6asm_async_read_compressed(prtd->audio_client,
 				&read_param);
 			break;
+		default:
+			pr_err("Invalid format");
+			ret = -EINVAL;
+			break;
 		}
 	}
 	prtd->periods = runtime->periods;
 
 	prtd->enabled = 1;
 
+	if (compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_PASS_THROUGH)
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					1);
+
 	return ret;
 }
 
@@ -539,7 +564,6 @@
 {
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 
@@ -547,28 +571,7 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		prtd->pcm_irq_pos = 0;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (compr->info.codec_param.codec.id ==
-				SND_AUDIOCODEC_AC3_PASS_THROUGH ||
-					compr->info.codec_param.codec.id ==
-					SND_AUDIOCODEC_DTS_PASS_THROUGH) {
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					1);
-			}
-		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			switch (compr->info.codec_param.codec.id) {
-			case SND_AUDIOCODEC_AMRWB:
-				break;
-			default:
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					1);
-				break;
-			}
-		}
+		/* intentional fall-through */
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: Trigger start\n", __func__);
@@ -576,29 +579,6 @@
 		atomic_set(&prtd->start, 1);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (compr->info.codec_param.codec.id ==
-					SND_AUDIOCODEC_AC3_PASS_THROUGH ||
-					compr->info.codec_param.codec.id ==
-					SND_AUDIOCODEC_DTS_PASS_THROUGH) {
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					0);
-			}
-		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			switch (compr->info.codec_param.codec.id) {
-			case SND_AUDIOCODEC_AMRWB:
-				break;
-			default:
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					0);
-				break;
-			}
-		}
 		atomic_set(&prtd->start, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -620,7 +600,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 10;
+	compr->info.compr_cap.num_codecs = 12;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -635,6 +615,8 @@
 	compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
 	compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
 	compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
+	compr->info.compr_cap.codecs[10] = SND_AUDIOCODEC_PASS_THROUGH;
+	compr->info.compr_cap.codecs[11] = SND_AUDIOCODEC_PCM;
 	/* Add new codecs here and update num_codecs*/
 }
 
@@ -753,11 +735,18 @@
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
-	if (!(compr->info.codec_param.codec.id ==
-			SND_AUDIOCODEC_AC3_PASS_THROUGH))
+	if ((compr->info.codec_param.codec.id !=
+			SND_AUDIOCODEC_AC3_PASS_THROUGH) &&
+			(compr->info.codec_param.codec.id !=
+			SND_AUDIOCODEC_DTS_PASS_THROUGH))
 		msm_pcm_routing_dereg_phy_stream(
 			soc_prtd->dai_link->be_id,
 			SNDRV_PCM_STREAM_PLAYBACK);
+	else
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					0);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -776,8 +765,15 @@
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
-	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-				SNDRV_PCM_STREAM_CAPTURE);
+	if (compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_PASS_THROUGH)
+		msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream,
+					0);
+	else
+		msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+					SNDRV_PCM_STREAM_CAPTURE);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 
@@ -909,12 +905,30 @@
 					prtd->audio_client->perf_mode,
 					prtd->session_id, substream->stream);
 			break;
-		default:
+		case SND_AUDIOCODEC_PCM:
+			pr_debug("q6asm_open_read(FORMAT_PCM)\n");
+			ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+			if (ret < 0) {
+				pr_err("%s: compressed Session open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			pr_debug("msm_pcm_routing_reg_phy_stream\n");
+			msm_pcm_routing_reg_phy_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->audio_client->perf_mode,
+					prtd->session_id, substream->stream);
+			break;
+		case SND_AUDIOCODEC_PASS_THROUGH:
 			pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
 			ret = q6asm_open_read_compressed(prtd->audio_client,
 				MAX_NUM_FRAMES_PER_BUFFER,
 				COMPRESSED_META_DATA_MODE);
 			break;
+		default:
+			pr_err("Invalid codec for compressed session open\n");
+			return -EFAULT;
 		}
 
 		if (ret < 0) {
@@ -1047,13 +1061,37 @@
 			pr_debug("SND_AUDIOCODEC_DTS_PASS_THROUGH\n");
 			compr->codec = FORMAT_DTS;
 			break;
-		case SND_AUDIOCODEC_DTS:
+		case SND_AUDIOCODEC_DTS: {
+			char modelId[128];
+			struct snd_dec_dts opt_dts =
+				compr->info.codec_param.codec.options.dts;
+			int modelIdLength = opt_dts.modelIdLength;
 			pr_debug("SND_AUDIOCODEC_DTS\n");
+			if (copy_from_user(modelId, (void *)opt_dts.modelId,
+				modelIdLength))
+				pr_err("%s: ERROR: copy modelId\n", __func__);
+			modelId[modelIdLength] = '\0';
+			pr_debug("%s: Received modelId =%s,length=%d\n",
+				__func__, modelId, modelIdLength);
+			core_set_dts_model_id(modelIdLength, modelId);
 			compr->codec = FORMAT_DTS;
+			}
 			break;
-		case SND_AUDIOCODEC_DTS_LBR:
-			pr_debug("SND_AUDIOCODEC_DTS\n");
+		case SND_AUDIOCODEC_DTS_LBR:{
+			char modelId[128];
+			struct snd_dec_dts opt_dts =
+				compr->info.codec_param.codec.options.dts;
+			int modelIdLength = opt_dts.modelIdLength;
+			pr_debug("SND_AUDIOCODEC_DTS_LBR\n");
+			if (copy_from_user(modelId, (void *)opt_dts.modelId,
+					modelIdLength))
+				pr_err("%s: ERROR: copy modelId\n", __func__);
+			modelId[modelIdLength] = '\0';
+			pr_debug("%s: Received modelId =%s,length=%d\n",
+				__func__, modelId, modelIdLength);
+			core_set_dts_model_id(modelIdLength, modelId);
 			compr->codec = FORMAT_DTS_LBR;
+			}
 			break;
 		case SND_AUDIOCODEC_AMRWB:
 			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWB\n");
@@ -1063,11 +1101,19 @@
 			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWBPLUS\n");
 			compr->codec = FORMAT_AMR_WB_PLUS;
 			break;
-		default:
-			/*Needed for the HDMI IN compressed use case*/
-			pr_debug("FORMAT_LINEAR_PCM\n");
-			compr->codec = FORMAT_LINEAR_PCM;
+		case SND_AUDIOCODEC_PASS_THROUGH:
+			/* format pass through is used for HDMI IN compressed
+			   where the decoder format is indicated by LPASS */
+			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_PASSTHROUGH\n");
+			compr->codec = FORMAT_PASS_THROUGH;
 			break;
+		case SND_AUDIOCODEC_PCM:
+			pr_debug("msm_compr_ioctl SND_AUDIOCODEC_PCM\n");
+			compr->codec = FORMAT_MULTI_CHANNEL_LINEAR_PCM;
+			break;
+		default:
+			pr_err("msm_compr_ioctl failed..unknown codec\n");
+			return -EFAULT;
 		}
 		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 59d118e..6ec44bf 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1018,6 +1018,8 @@
 	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
 			channels->min, channels->max);
 
+	if (channels->max < 2)
+		channels->min = channels->max = 2;
 	rate->min = rate->max = 48000;
 
 	return 0;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 92b7324..f462299 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -81,6 +81,7 @@
 static int msm_slim_0_tx_ch = 1;
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
@@ -480,6 +481,21 @@
 		     msm_btsco_rate_get, msm_btsco_rate_put),
 };
 
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = msm_btsco_rate;
+	channels->min = channels->max = msm_btsco_ch;
+
+	return 0;
+}
+
 static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -495,6 +511,19 @@
 
 	return 0;
 }
+
+static int msm_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
 static int msm_aux_pcm_get_gpios(void)
 {
 	int ret = 0;
@@ -780,19 +809,19 @@
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
 	},
 	{
-		.name = "MSM VoIP",
-		.stream_name = "VoIP",
-		.cpu_dai_name	= "VoIP",
-		.platform_name  = "msm-voip-dsp",
+		.name = "MSM8974 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name   = "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
 		.ignore_suspend = 1,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_VOIP,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
 	},
 	{
 		.name = "Circuit-Switch Voice",
@@ -811,6 +840,21 @@
 		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
 	},
 	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_VOIP,
+	},
+	{
 		.name = "MSM8974 LPA",
 		.stream_name = "LPA",
 		.cpu_dai_name	= "MultiMedia3",
@@ -841,6 +885,41 @@
 		.codec_name = "snd-soc-dummy",
 	},
 	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6-dev.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6-dev.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
 		.name = "MSM8974 Compr",
 		.stream_name = "COMPR",
 		.cpu_dai_name	= "MultiMedia4",
@@ -870,19 +949,55 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	/* Backend BT/FM DAI Links */
 	{
-		.name = "MSM8974 Media2",
-		.stream_name = "MultiMedia2",
-		.cpu_dai_name	= "MultiMedia2",
-		.platform_name = "msm-pcm-dsp",
-		.dynamic = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.ignore_suspend = 1,
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.12288",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
-		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.224",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
 	},
 	/* AUX PCM Backend DAI Links */
 	{
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index b8eb1df..0aad217 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -798,6 +798,25 @@
 	return 0;
 }
 
+static int32_t is_no_wait_cmd_rsp(uint32_t opcode, uint32_t *cmd_type)
+{
+	if (opcode == APR_BASIC_RSP_RESULT) {
+		if (cmd_type != NULL) {
+			switch (cmd_type[0]) {
+			case ASM_SESSION_CMD_RUN:
+			case ASM_SESSION_CMD_PAUSE:
+			case ASM_DATA_CMD_EOS:
+				return 1;
+			default:
+				break;
+			}
+		} else
+			pr_err("%s: null pointer!", __func__);
+	} else if (opcode == ASM_DATA_CMDRSP_EOS)
+		return 1;
+
+	return 0;
+}
 
 static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
 {
@@ -818,14 +837,16 @@
 			ac->session);
 		return -EINVAL;
 	}
-	if (atomic_read(&ac->nowait_cmd_cnt) > 0) {
+
+	payload = data->payload;
+	if ((atomic_read(&ac->nowait_cmd_cnt) > 0) &&
+		is_no_wait_cmd_rsp(data->opcode, payload)) {
 		pr_debug("%s: nowait_cmd_cnt %d\n",
 				__func__,
 				atomic_read(&ac->nowait_cmd_cnt));
 		atomic_dec(&ac->nowait_cmd_cnt);
 		wakeup_flag = 0;
 	}
-	payload = data->payload;
 
 	if (data->opcode == RESET_EVENTS) {
 		pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
@@ -875,8 +896,9 @@
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
-				if (payload[1] == ADSP_EUNSUPPORTED) {
-					pr_debug("paload[1]:%d unsupported",
+				if (payload[1] == ADSP_EUNSUPPORTED ||
+					payload[1] == ADSP_EFAILED) {
+					pr_debug("payload[1]:%d unsupported",
 								payload[1]);
 					atomic_set(&ac->cmd_response, 1);
 				}
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6f3249a..bbd43f7 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -25,13 +25,25 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm_params.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
+#include <sound/timer.h>
 
 #include "msm-compr-q6-v2.h"
 #include "msm-pcm-routing-v2.h"
 
+#define COMPRE_CAPTURE_NUM_PERIODS	16
+/* Allocate the worst case frame size for compressed audio */
+#define COMPRE_CAPTURE_HEADER_SIZE	(sizeof(struct snd_compr_audio_info))
+#define COMPRE_CAPTURE_MAX_FRAME_SIZE	(6144)
+#define COMPRE_CAPTURE_PERIOD_SIZE	((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
+					  COMPRE_CAPTURE_HEADER_SIZE) * \
+					  MAX_NUM_FRAMES_PER_BUFFER)
+#define COMPRE_OUTPUT_METADATA_SIZE	(sizeof(struct output_meta_data_st))
+
 struct snd_msm {
 	struct msm_audio *prtd;
 	unsigned volume;
@@ -40,7 +52,7 @@
 
 static struct audio_locks the_locks;
 
-static struct snd_pcm_hardware msm_compr_hardware_playback = {
+static struct snd_pcm_hardware msm_compr_hardware_capture = {
 	.info =		 (SNDRV_PCM_INFO_MMAP |
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				SNDRV_PCM_INFO_MMAP_VALID |
@@ -51,12 +63,33 @@
 	.rate_min =	     8000,
 	.rate_max =	     48000,
 	.channels_min =	 1,
-	.channels_max =	 2,
+	.channels_max =	 8,
+	.buffer_bytes_max =
+		COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS ,
+	.period_bytes_min =	COMPRE_CAPTURE_PERIOD_SIZE,
+	.period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
+	.periods_min =	  COMPRE_CAPTURE_NUM_PERIODS,
+	.periods_max =	  COMPRE_CAPTURE_NUM_PERIODS,
+	.fifo_size =	    0,
+};
+
+static struct snd_pcm_hardware msm_compr_hardware_playback = {
+	.info =		 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+	.rate_min =	     8000,
+	.rate_max =	     48000,
+	.channels_min =	 1,
+	.channels_max =	 8,
 	.buffer_bytes_max =     1200 * 1024 * 2,
-	.period_bytes_min =	4800,
+	.period_bytes_min =	2400,
 	.period_bytes_max =     1200 * 1024,
 	.periods_min =	  2,
-	.periods_max =	  512,
+	.periods_max =	  1024,
 	.fifo_size =	    0,
 };
 
@@ -79,8 +112,13 @@
 	struct snd_pcm_substream *substream = prtd->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct audio_aio_write_param param;
+	struct audio_aio_read_param read_param;
 	struct audio_buffer *buf = NULL;
+	struct output_meta_data_st output_meta_data;
+	uint32_t *ptrmem = (uint32_t *)payload;
 	int i = 0;
+	int time_stamp_flag = 0;
+	int buffer_length = 0;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -91,6 +129,9 @@
 		prtd->pcm_irq_pos += prtd->pcm_count;
 		if (atomic_read(&prtd->start))
 			snd_pcm_period_elapsed(substream);
+		else
+			if (substream->timer_running)
+				snd_timer_interrupt(substream->timer, 1);
 		atomic_inc(&prtd->out_count);
 		wake_up(&the_locks.write_wait);
 		if (!atomic_read(&prtd->start)) {
@@ -98,9 +139,6 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
-			break;
 		buf = prtd->audio_client->port[IN].buf;
 		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
 				__func__, prtd->pcm_count, prtd->out_head);
@@ -109,14 +147,38 @@
 				((unsigned int)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count)));
 
+		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+			time_stamp_flag = SET_TIMESTAMP;
+			memcpy(&output_meta_data, (char *)(buf->data +
+			prtd->out_head * prtd->pcm_count),
+			COMPRE_OUTPUT_METADATA_SIZE);
+		} else {
+			time_stamp_flag = NO_TIMESTAMP;
+			memset(&output_meta_data, 0,
+				 COMPRE_OUTPUT_METADATA_SIZE);
+			output_meta_data.frame_size = prtd->pcm_count;
+		}
+		buffer_length = output_meta_data.frame_size;
+		pr_debug("meta_data_length: %d, frame_length: %d\n",
+			 output_meta_data.meta_data_length,
+			 output_meta_data.frame_size);
+		pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+			 output_meta_data.timestamp_msw,
+			 output_meta_data.timestamp_lsw);
+		if (buffer_length == 0) {
+			pr_debug("Recieved a zero length buffer-break out");
+			break;
+		}
 		param.paddr = (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count);
-		param.len = prtd->pcm_count;
-		param.msw_ts = 0;
-		param.lsw_ts = 0;
-		param.flags = NO_TIMESTAMP;
+				+ (prtd->out_head * prtd->pcm_count)
+				+ output_meta_data.meta_data_length;
+		param.len = buffer_length;
+		param.msw_ts = output_meta_data.timestamp_msw;
+		param.lsw_ts = output_meta_data.timestamp_lsw;
+		param.flags = time_stamp_flag;
 		param.uid =  (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count);
+				+ (prtd->out_head * prtd->pcm_count
+				+ output_meta_data.meta_data_length);
 		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
 					i++, ++ptrmem)
 			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
@@ -131,12 +193,60 @@
 	}
 	case ASM_DATA_EVENT_RENDERED_EOS:
 		pr_debug("ASM_DATA_CMDRSP_EOS\n");
-		prtd->cmd_ack = 1;
-		wake_up(&the_locks.eos_wait);
+		if (atomic_read(&prtd->eos)) {
+			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.eos_wait);
+			atomic_set(&prtd->eos, 0);
+		}
 		break;
+	case ASM_DATA_EVENT_READ_DONE_V2: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("buf = %p, data = 0x%X, *data = %p,\n"
+			 "prtd->pcm_irq_pos = %d\n",
+				prtd->audio_client->port[OUT].buf,
+			 *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
+				prtd->audio_client->port[OUT].buf->data,
+				prtd->pcm_irq_pos);
+
+		memcpy(prtd->audio_client->port[OUT].buf->data +
+			   prtd->pcm_irq_pos, (ptrmem + 2),
+			   COMPRE_CAPTURE_HEADER_SIZE);
+		pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
+				prtd->audio_client->port[OUT].buf,
+			*(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
+				prtd->pcm_irq_pos),
+				prtd->audio_client->port[OUT].buf->data);
+		if (!atomic_read(&prtd->start))
+			break;
+		pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
+				ptrmem[1]);
+		if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+			pr_err("Frame length exceeded the max length");
+			break;
+		}
+		buf = prtd->audio_client->port[OUT].buf;
+		pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
+				prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
+		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
+		read_param.paddr = (unsigned long)(buf[0].phys) +
+			prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
+		prtd->pcm_irq_pos += prtd->pcm_count;
+
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+
+		q6asm_async_read(prtd->audio_client, &read_param);
+		break;
+	}
 	case APR_BASIC_RSP_RESULT: {
 		switch (payload[0]) {
 		case ASM_SESSION_CMD_RUN_V2: {
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK) {
+				atomic_set(&prtd->start, 1);
+				break;
+			}
 			if (!atomic_read(&prtd->pending_buffer))
 				break;
 			pr_debug("%s:writing %d bytes of buffer[%d] to dsp\n",
@@ -146,12 +256,32 @@
 				__func__, prtd->out_head,
 				((unsigned int)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count)));
-			param.paddr = (unsigned long)buf[prtd->out_head].phys;
-			param.len = prtd->pcm_count;
-			param.msw_ts = 0;
-			param.lsw_ts = 0;
-			param.flags = NO_TIMESTAMP;
-			param.uid =  (unsigned long)buf[prtd->out_head].phys;
+			if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+				time_stamp_flag = SET_TIMESTAMP;
+				memcpy(&output_meta_data, (char *)(buf->data +
+				prtd->out_head * prtd->pcm_count),
+				COMPRE_OUTPUT_METADATA_SIZE);
+			} else {
+				time_stamp_flag = NO_TIMESTAMP;
+				memset(&output_meta_data, 0,
+				 COMPRE_OUTPUT_METADATA_SIZE);
+				output_meta_data.frame_size = prtd->pcm_count;
+			}
+			buffer_length = output_meta_data.frame_size;
+			pr_debug("meta_data_length: %d, frame_length: %d\n",
+				 output_meta_data.meta_data_length,
+				 output_meta_data.frame_size);
+			pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+				 output_meta_data.timestamp_msw,
+				 output_meta_data.timestamp_lsw);
+			param.paddr = (unsigned long)buf[prtd->out_head].phys
+					+ output_meta_data.meta_data_length;
+			param.len = buffer_length;
+			param.msw_ts = output_meta_data.timestamp_msw;
+			param.lsw_ts = output_meta_data.timestamp_lsw;
+			param.flags = time_stamp_flag;
+			param.uid =  (unsigned long)buf[prtd->out_head].phys
+					+ output_meta_data.meta_data_length;
 			if (q6asm_async_write(prtd->audio_client,
 						&param) < 0)
 				pr_err("%s:q6asm_async_write failed\n",
@@ -166,7 +296,7 @@
 		case ASM_STREAM_CMD_FLUSH:
 			pr_debug("ASM_STREAM_CMD_FLUSH\n");
 			prtd->cmd_ack = 1;
-			wake_up(&the_locks.eos_wait);
+			wake_up(&the_locks.flush_wait);
 			break;
 		default:
 			break;
@@ -187,7 +317,7 @@
 	struct asm_aac_cfg aac_cfg;
 	int ret;
 
-	pr_debug("%s\n", __func__);
+	pr_debug("compressed stream prepare\n");
 	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
 	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
 	prtd->pcm_irq_pos = 0;
@@ -205,7 +335,7 @@
 		/* No media format block for mp3 */
 		break;
 	case SND_AUDIOCODEC_AAC:
-		pr_debug("SND_AUDIOCODEC_AAC\n");
+		pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
 		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
 		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
 		aac_cfg.format = 0x03;
@@ -226,10 +356,83 @@
 	return 0;
 }
 
+static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+	struct snd_codec *codec = &compr->info.codec_param.codec;
+	struct audio_aio_read_param read_param;
+	int ret = 0;
+	int i;
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return ret;
+	read_param.len = prtd->pcm_count;
+
+	switch (codec->id) {
+	case SND_AUDIOCODEC_AMRWB:
+		pr_debug("SND_AUDIOCODEC_AMRWB\n");
+		ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+			MAX_NUM_FRAMES_PER_BUFFER,
+			codec->options.generic.reserved[0] /*bitrate 0-8*/,
+			codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+		if (ret < 0)
+			pr_err("%s: CMD Format block" \
+				"failed: %d\n", __func__, ret);
+		break;
+	default:
+		pr_debug("No config for codec %d\n", codec->id);
+	}
+	pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
+			 "pcm_count = %d, periods = %d\n",
+			 __func__, prtd->samp_rate, prtd->channel_mode,
+			 prtd->pcm_size, prtd->pcm_count, runtime->periods);
+
+	for (i = 0; i < runtime->periods; i++) {
+		read_param.uid = i;
+		switch (codec->id) {
+		case SND_AUDIOCODEC_AMRWB:
+			read_param.len = prtd->pcm_count
+					- COMPRE_CAPTURE_HEADER_SIZE;
+			read_param.paddr = (unsigned long)(buf[i].phys)
+					+ COMPRE_CAPTURE_HEADER_SIZE;
+			pr_debug("Push buffer [%d] to DSP, "\
+					"paddr: %p, vaddr: %p\n",
+					i, (void *) read_param.paddr,
+					buf[i].data);
+			q6asm_async_read(prtd->audio_client, &read_param);
+			break;
+		default:
+			read_param.paddr = (unsigned long)(buf[i].phys);
+			/*q6asm_async_read_compressed(prtd->audio_client,
+				&read_param);*/
+			pr_debug("%s: To add support for read compressed\n",
+								__func__);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
 static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 
@@ -237,6 +440,17 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		prtd->pcm_irq_pos = 0;
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream);
+				break;
+			}
+		}
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: Trigger start\n", __func__);
@@ -245,6 +459,17 @@
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			switch (compr->info.codec_param.codec.id) {
+			case SND_AUDIOCODEC_AMRWB:
+				break;
+			default:
+				msm_pcm_routing_reg_psthr_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream);
+				break;
+			}
+		}
 		atomic_set(&prtd->start, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -266,7 +491,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 1;
+	compr->info.compr_cap.num_codecs = 2;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -294,10 +519,6 @@
 		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
 	};
 
-	/* Capture path */
-	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		return -EINVAL;
-
 	pr_debug("%s\n", __func__);
 	compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
 	if (compr == NULL) {
@@ -313,12 +534,18 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
-	runtime->hw = msm_compr_hardware_playback;
 
 	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
 
 	prtd->session_id = prtd->audio_client->session;
-	prtd->cmd_ack = 1;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw = msm_compr_hardware_playback;
+		prtd->cmd_ack = 1;
+	} else {
+		runtime->hw = msm_compr_hardware_capture;
+	}
+
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 			SNDRV_PCM_HW_PARAM_RATE,
@@ -333,9 +560,11 @@
 
 	prtd->dsp_cnt = 0;
 	atomic_set(&prtd->pending_buffer, 1);
-	compr->codec = FORMAT_MP3;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		compr->codec = FORMAT_MP3;
 	populate_codec_list(compr, runtime);
 	runtime->private_data = compr;
+	atomic_set(&prtd->eos, 0);
 	compressed_audio.prtd =  &compr->prtd;
 	ret = compressed_set_volume(compressed_audio.volume);
 	if (ret < 0)
@@ -382,13 +611,34 @@
 
 	dir = IN;
 	atomic_set(&prtd->pending_buffer, 0);
+	prtd->pcm_irq_pos = 0;
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
+		msm_pcm_routing_dereg_phy_stream(
+			soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
 
+static int msm_compr_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct compr_audio *compr = runtime->private_data;
+	struct msm_audio *prtd = &compr->prtd;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	atomic_set(&prtd->pending_buffer, 0);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-	SNDRV_PCM_STREAM_PLAYBACK);
+				SNDRV_PCM_STREAM_CAPTURE);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -401,7 +651,7 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		ret = msm_compr_playback_close(substream);
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		ret = EINVAL;
+		ret = msm_compr_capture_close(substream);
 	return ret;
 }
 static int msm_compr_prepare(struct snd_pcm_substream *substream)
@@ -411,7 +661,7 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		ret = msm_compr_playback_prepare(substream);
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		ret = EINVAL;
+		ret = msm_compr_capture_prepare(substream);
 	return ret;
 }
 
@@ -425,7 +675,10 @@
 	if (prtd->pcm_irq_pos >= prtd->pcm_size)
 		prtd->pcm_irq_pos = 0;
 
-	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
+			 "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
+			 prtd->pcm_size, runtime->sample_bits,
+			 runtime->frame_bits);
 	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
 }
 
@@ -467,22 +720,69 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
 	else
-		return -EINVAL;
+		dir = OUT;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			ret = q6asm_open_write(prtd->audio_client,
+					compr->codec);
+			if (ret < 0) {
+				pr_err("%s: Session out open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			msm_pcm_routing_reg_phy_stream(
+				soc_prtd->dai_link->be_id,
+				prtd->session_id,
+				substream->stream);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		switch (compr->info.codec_param.codec.id) {
+		case SND_AUDIOCODEC_AMRWB:
+			pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+			ret = q6asm_open_read(prtd->audio_client,
+				FORMAT_AMRWB);
+			if (ret < 0) {
+				pr_err("%s: compressed Session out open failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			pr_debug("msm_pcm_routing_reg_phy_stream\n");
+			msm_pcm_routing_reg_phy_stream(
+					soc_prtd->dai_link->be_id,
+					prtd->session_id, substream->stream);
+			break;
+		default:
+			pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+			/*
+			ret = q6asm_open_read_compressed(prtd->audio_client,
+				MAX_NUM_FRAMES_PER_BUFFER,
+				COMPRESSED_META_DATA_MODE);
+			*/
+			ret = -EINVAL;
+			break;
+		}
 
-	ret = q6asm_open_write(prtd->audio_client, compr->codec);
-	if (ret < 0) {
-		pr_err("%s: Session out open failed\n", __func__);
-		return -ENOMEM;
+		if (ret < 0) {
+			pr_err("%s: compressed Session out open failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 	}
-	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
-			prtd->session_id, substream->stream);
 
 	ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
 		return -ENOMEM;
 	}
-
+	/* Modifying kernel hardware params based on userspace config */
+	if (params_periods(params) > 0 &&
+		(params_periods(params) != runtime->hw.periods_max)) {
+		runtime->hw.periods_max = params_periods(params);
+	}
+	if (params_period_bytes(params) > 0 &&
+		(params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+		runtime->hw.period_bytes_min = params_period_bytes(params);
+	}
+	runtime->hw.buffer_bytes_max =
+			runtime->hw.period_bytes_min * runtime->hw.periods_max;
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
@@ -494,13 +794,17 @@
 	}
 	buf = prtd->audio_client->port[dir].buf;
 
-	pr_debug("%s:buf = %p\n", __func__, buf);
 	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
 	dma_buf->dev.dev = substream->pcm->card->dev;
 	dma_buf->private_data = NULL;
 	dma_buf->area = buf[0].data;
 	dma_buf->addr =  buf[0].phys;
 	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+
+	pr_debug("%s: buf[%p]dma_buf->area[%p]dma_buf->addr[%p]\n"
+		 "dma_buf->bytes[%d]\n", __func__,
+		 (void *)buf, (void *)dma_buf->area,
+		 (void *)dma_buf->addr, dma_buf->bytes);
 	if (!dma_buf->area)
 		return -ENOMEM;
 
@@ -577,16 +881,47 @@
 		}
 		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
-		prtd->cmd_ack = 0;
-		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
-		if (rc < 0)
-			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
-		rc = wait_event_timeout(the_locks.eos_wait,
-			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
-			pr_err("Flush cmd timeout\n");
-		prtd->pcm_irq_pos = 0;
+		pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+		/* Flush only when session is started during CAPTURE,
+		   while PLAYBACK has no such restriction. */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+			  (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+						atomic_read(&prtd->start))) {
+			if (atomic_read(&prtd->eos)) {
+				prtd->cmd_ack = 1;
+				wake_up(&the_locks.eos_wait);
+				atomic_set(&prtd->eos, 0);
+			}
+
+			/* A unlikely race condition possible with FLUSH
+			   DRAIN if ack is set by flush and reset by drain */
+			prtd->cmd_ack = 0;
+			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			if (rc < 0) {
+				pr_err("%s: flush cmd failed rc=%d\n",
+					__func__, rc);
+				return rc;
+			}
+			rc = wait_event_timeout(the_locks.flush_wait,
+				prtd->cmd_ack, 5 * HZ);
+			if (rc < 0)
+				pr_err("Flush cmd timeout\n");
+			prtd->pcm_irq_pos = 0;
+		}
 		break;
+	case SNDRV_COMPRESS_DRAIN:
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
+		atomic_set(&prtd->eos, 1);
+		atomic_set(&prtd->pending_buffer, 0);
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		/* Wait indefinitely for  DRAIN. Flush can also signal this*/
+		rc = wait_event_interruptible(the_locks.eos_wait,
+			prtd->cmd_ack);
+		if (rc < 0)
+			pr_err("EOS cmd interrupted\n");
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN  out of wait\n", __func__);
+		return 0;
 	default:
 		break;
 	}
@@ -658,6 +993,7 @@
 	init_waitqueue_head(&the_locks.eos_wait);
 	init_waitqueue_head(&the_locks.write_wait);
 	init_waitqueue_head(&the_locks.read_wait);
+	init_waitqueue_head(&the_locks.flush_wait);
 
 	return platform_driver_register(&msm_compr_driver);
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 3eab972..a6cdad2 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -540,6 +540,14 @@
 
 	memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
 
+	pr_debug("%s: setting bt_fm parameters\n", __func__);
+
+	dai_data->port_config.int_bt_fm.bt_fm_cfg_minor_version =
+					AFE_API_VERSION_INTERNAL_BT_FM_CONFIG;
+	dai_data->port_config.int_bt_fm.num_channels = dai_data->channels;
+	dai_data->port_config.int_bt_fm.sample_rate = dai_data->rate;
+	dai_data->port_config.int_bt_fm.bit_width = 16;
+
 	return 0;
 }
 
@@ -805,6 +813,36 @@
 	return 0;
 }
 
+static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 4,
+		.rate_min =     8000,
+		.rate_max =	48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
 	.playback = {
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
@@ -833,6 +871,34 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 16000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 1,
+		.rate_max = 16000,
+		.rate_min = 8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
 {
 	int id;
@@ -1084,6 +1150,22 @@
 		rc = snd_soc_register_dai(&pdev->dev,
 					  &msm_dai_q6_slimbus_1_tx_dai);
 		break;
+	case INT_BT_SCO_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_bt_sco_rx_dai);
+		break;
+	case INT_BT_SCO_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_bt_sco_tx_dai);
+		break;
+	case RT_PROXY_DAI_001_RX:
+	case RT_PROXY_DAI_002_RX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
+		break;
+	case RT_PROXY_DAI_001_TX:
+	case RT_PROXY_DAI_002_TX:
+		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
+		break;
 	default:
 		rc = -ENODEV;
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 4593784..73a04c2 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -29,6 +29,8 @@
 #include <sound/control.h>
 #include <sound/q6adm-v2.h>
 #include <asm/dma.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_subsystem_map.h>
 #include "msm-pcm-afe-v2.h"
 
 #define MIN_PERIOD_SIZE (128 * 2)
@@ -63,6 +65,11 @@
 	struct snd_pcm_substream *substream = prtd->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	u32 mem_map_handle = 0;
+
+	mem_map_handle = afe_req_mmap_handle();
+	if (!mem_map_handle)
+		pr_err("%s: mem_map_handle is NULL\n", __func__);
+
 	if (prtd->start) {
 		pr_debug("sending frame to DSP: poll_time: %d\n",
 				prtd->poll_time);
@@ -89,10 +96,15 @@
 	struct snd_pcm_substream *substream = prtd->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	u32 mem_map_handle = 0;
+
+	mem_map_handle = afe_req_mmap_handle();
+	if (!mem_map_handle)
+		pr_err("%s: mem_map_handle is NULL\n", __func__);
+
 	if (prtd->start) {
 		if (prtd->dsp_cnt == runtime->periods)
 			prtd->dsp_cnt = 0;
-		pr_err("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
+		pr_debug("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
 		afe_rt_proxy_port_read(
 		(prtd->dma_addr + (prtd->dsp_cnt
 		* snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle,
@@ -137,9 +149,6 @@
 						runtime->channels * 2)));
 				pr_debug("prtd->poll_time: %d",
 						prtd->poll_time);
-				hrtimer_start(&prtd->hrt,
-					ns_to_ktime(0),
-					HRTIMER_MODE_REL);
 				break;
 			}
 			case AFE_EVENT_RTPORT_STOP:
@@ -203,9 +212,6 @@
 				snd_pcm_lib_period_bytes(prtd->substream)
 					* 1000 * 1000)/(runtime->rate
 					* runtime->channels * 2)));
-			hrtimer_start(&prtd->hrt,
-				ns_to_ktime(0),
-				HRTIMER_MODE_REL);
 			pr_debug("prtd->poll_time : %d", prtd->poll_time);
 			break;
 		}
@@ -321,13 +327,21 @@
 	runtime->hw = msm_afe_hardware;
 	prtd->substream = substream;
 	runtime->private_data = prtd;
-	mutex_unlock(&prtd->lock);
+	prtd->audio_client = q6afe_audio_client_alloc(prtd);
+	if (!prtd->audio_client) {
+		pr_debug("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+
 	hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		prtd->hrt.function = afe_hrtimer_callback;
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		prtd->hrt.function = afe_hrtimer_rec_callback;
 
+	mutex_unlock(&prtd->lock);
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 				SNDRV_PCM_HW_PARAM_RATE,
 				&constraints_sample_rates);
@@ -350,6 +364,7 @@
 	struct pcm_afe_info *prtd;
 	struct snd_soc_pcm_runtime *rtd = NULL;
 	struct snd_soc_dai *dai = NULL;
+	int dir = IN;
 	int ret = 0;
 
 	pr_debug("%s\n", __func__);
@@ -365,17 +380,19 @@
 	mutex_lock(&prtd->lock);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dir = IN;
 		ret =  afe_unregister_get_events(dai->id);
 		if (ret < 0)
 			pr_err("AFE unregister for events failed\n");
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		dir = OUT;
 		ret =  afe_unregister_get_events(dai->id);
 		if (ret < 0)
 			pr_err("AFE unregister for events failed\n");
 	}
 	hrtimer_cancel(&prtd->hrt);
 
-	rc = afe_cmd_memory_unmap(runtime->dma_addr);
+	rc = afe_cmd_memory_unmap(afe_req_mmap_handle());
 	if (rc < 0)
 		pr_err("AFE memory unmap failed\n");
 
@@ -384,15 +401,14 @@
 	if (dma_buf == NULL) {
 		pr_debug("dma_buf is NULL\n");
 			goto done;
-		}
-	if (dma_buf->area != NULL) {
-		dma_free_coherent(substream->pcm->card->dev,
-			runtime->hw.buffer_bytes_max, dma_buf->area,
-			dma_buf->addr);
-		dma_buf->area = NULL;
 	}
+
+	if (dma_buf->area)
+		dma_buf->area = NULL;
+	q6afe_audio_client_buf_free_contiguous(dir, prtd->audio_client);
 done:
 	pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+	q6afe_audio_client_free(prtd->audio_client);
 	mutex_unlock(&prtd->lock);
 	prtd->prepared--;
 	kfree(prtd);
@@ -420,14 +436,21 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct pcm_afe_info *prtd = runtime->private_data;
+	int result = 0;
 
 	pr_debug("%s\n", __func__);
 	prtd->mmap_flag = 1;
-	dma_mmap_coherent(substream->pcm->card->dev, vma,
-				runtime->dma_area,
-				runtime->dma_addr,
-				runtime->dma_bytes);
-	return 0;
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+	return result;
 }
 static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
 {
@@ -441,6 +464,8 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
 		prtd->start = 1;
+		hrtimer_start(&prtd->hrt, ns_to_ktime(0),
+					HRTIMER_MODE_REL);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -460,27 +485,45 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct pcm_afe_info *prtd = runtime->private_data;
-	int rc;
+	struct afe_audio_buffer *buf;
+	int dir, rc;
 
 	pr_debug("%s:\n", __func__);
 
 	mutex_lock(&prtd->lock);
-
-	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	dma_buf->dev.dev = substream->pcm->card->dev;
-	dma_buf->private_data = NULL;
-	dma_buf->area = dma_alloc_coherent(dma_buf->dev.dev,
-				runtime->hw.buffer_bytes_max,
-				&dma_buf->addr, GFP_KERNEL);
-
-	pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
-			(unsigned int *) dma_buf->area, dma_buf->addr);
-	if (!dma_buf->area) {
-		pr_err("%s:MSM AFE memory allocation failed\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+	rc = q6afe_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (rc < 0) {
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", rc);
 		mutex_unlock(&prtd->lock);
 		return -ENOMEM;
 	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	if (buf == NULL || buf[0].data == NULL) {
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr = buf[0].phys;
 	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area) {
+		pr_err("%s:MSM AFE physical memory allocation failed\n",
+							__func__);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
 	memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
 	prtd->dma_addr = (u32) dma_buf->addr;
 
@@ -542,6 +585,9 @@
 
 static __devinit int msm_afe_probe(struct platform_device *pdev)
 {
+	if (pdev->dev.of_node)
+		dev_set_name(&pdev->dev, "%s", "msm-pcm-afe");
+
 	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
 	return snd_soc_register_platform(&pdev->dev,
 				   &msm_soc_platform);
@@ -553,11 +599,17 @@
 	snd_soc_unregister_platform(&pdev->dev);
 	return 0;
 }
+static const struct of_device_id msm_pcm_afe_dt_match[] = {
+	{.compatible = "qcom,msm-pcm-afe"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_pcm_afe_dt_match);
 
 static struct platform_driver msm_afe_driver = {
 	.driver = {
 		.name = "msm-pcm-afe",
 		.owner = THIS_MODULE,
+		.of_match_table = msm_pcm_afe_dt_match,
 	},
 	.probe = msm_afe_probe,
 	.remove = __devexit_p(msm_afe_remove),
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
index 20d6377..446409f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
@@ -30,6 +30,7 @@
 	int prepared;
 	struct hrtimer hrt;
 	int poll_time;
+	struct afe_audio_client *audio_client;
 };
 
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 22bf0cc..e25d356 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -49,6 +49,7 @@
 	wait_queue_head_t write_wait;
 	wait_queue_head_t eos_wait;
 	wait_queue_head_t enable_wait;
+	wait_queue_head_t flush_wait;
 };
 
 struct msm_audio {
@@ -76,10 +77,19 @@
 	atomic_t out_count;
 	atomic_t in_count;
 	atomic_t out_needed;
+	atomic_t eos;
 	int out_head;
 	int periods;
 	int mmap_flag;
 	atomic_t pending_buffer;
 };
 
+struct output_meta_data_st {
+	uint32_t meta_data_length;
+	uint32_t frame_size;
+	uint32_t timestamp_lsw;
+	uint32_t timestamp_msw;
+	uint32_t reserved[12];
+};
+
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 0b25545..f0465a5 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -18,6 +18,7 @@
 #include <linux/wait.h>
 #include <linux/jiffies.h>
 #include <linux/sched.h>
+#include <linux/msm_ion.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 #include <sound/apr_audio-v2.h>
 #include <sound/q6afe-v2.h>
@@ -37,6 +38,7 @@
 		uint32_t token, uint32_t *payload, void *priv);
 	void *tx_private_data;
 	void *rx_private_data;
+	uint32_t mmap_handle;
 };
 
 static struct afe_ctl this_afe;
@@ -107,6 +109,13 @@
 						payload[0]);
 				break;
 			}
+		} else if (data->opcode ==
+				AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS) {
+			pr_debug("%s: mmap_handle: 0x%x\n",
+						__func__, payload[0]);
+			this_afe.mmap_handle = (uint32_t)payload[0];
+			atomic_set(&this_afe.state, 0);
+			wake_up(&this_afe.wait[data->token]);
 		} else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
 			port_id = (uint16_t)(0x0000FFFF & payload[0]);
 		}
@@ -266,17 +275,21 @@
 		ret = -EINVAL;
 		return ret;
 	}
-	index = q6audio_get_port_index(port_id);
-	if (q6audio_validate_port(port_id) < 0)
-		return -EINVAL;
 
 	if ((port_id == RT_PROXY_DAI_001_RX) ||
 		(port_id == RT_PROXY_DAI_002_TX))
-		return -EINVAL;
+		return 0;
 	if ((port_id == RT_PROXY_DAI_002_RX) ||
 		(port_id == RT_PROXY_DAI_001_TX))
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
 
+	pr_debug("%s: port id: %d\n", __func__, port_id);
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: port id: %d\n", __func__, port_id);
+		return -EINVAL;
+	}
+
 	ret = afe_q6_interface_prepare();
 	if (IS_ERR_VALUE(ret))
 		return ret;
@@ -325,6 +338,14 @@
 	case SLIMBUS_4_TX:
 		cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
 		break;
+	case RT_PROXY_PORT_001_RX:
+	case RT_PROXY_PORT_001_TX:
+		cfg_type = AFE_PARAM_ID_RT_PROXY_CONFIG;
+		break;
+	case INT_BT_SCO_RX:
+	case INT_BT_SCO_TX:
+		cfg_type = AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG;
+		break;
 	default:
 		pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
 		ret = -EINVAL;
@@ -904,7 +925,133 @@
 	return 0;
 }
 
-/*bharath, memory map handle needs to be stored by AFE client */
+uint32_t afe_req_mmap_handle(void)
+{
+	return this_afe.mmap_handle;
+}
+
+struct afe_audio_client *q6afe_audio_client_alloc(void *priv)
+{
+	struct afe_audio_client *ac;
+	int lcnt = 0;
+
+	ac = kzalloc(sizeof(struct afe_audio_client), GFP_KERNEL);
+	if (!ac) {
+		pr_err("%s: cannot allocate audio client for afe\n", __func__);
+		return NULL;
+	}
+	ac->priv = priv;
+
+	init_waitqueue_head(&ac->cmd_wait);
+	INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
+	INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
+	pr_debug("%s: mem_map_handle list init'ed\n", __func__);
+	mutex_init(&ac->cmd_lock);
+	for (lcnt = 0; lcnt <= OUT; lcnt++) {
+		mutex_init(&ac->port[lcnt].lock);
+		spin_lock_init(&ac->port[lcnt].dsp_lock);
+	}
+	atomic_set(&ac->cmd_state, 0);
+
+	return ac;
+}
+
+int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir,
+			struct afe_audio_client *ac,
+			unsigned int bufsz,
+			unsigned int bufcnt)
+{
+	int cnt = 0;
+	int rc = 0;
+	struct afe_audio_buffer *buf;
+	int len;
+
+	if (!(ac) || ((dir != IN) && (dir != OUT)))
+		return -EINVAL;
+
+	pr_debug("%s: bufsz[%d]bufcnt[%d]\n",
+			__func__,
+			bufsz, bufcnt);
+
+	if (ac->port[dir].buf) {
+		pr_debug("%s: buffer already allocated\n", __func__);
+		return 0;
+	}
+	mutex_lock(&ac->cmd_lock);
+	buf = kzalloc(((sizeof(struct afe_audio_buffer))*bufcnt),
+			GFP_KERNEL);
+
+	if (!buf) {
+		mutex_unlock(&ac->cmd_lock);
+		goto fail;
+	}
+
+	ac->port[dir].buf = buf;
+
+	buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
+	if (IS_ERR_OR_NULL((void *)buf[0].client)) {
+		pr_err("%s: ION create client for AUDIO failed\n", __func__);
+		goto fail;
+	}
+	buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
+				  (0x1 << ION_AUDIO_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
+		pr_err("%s: ION memory allocation for AUDIO failed\n",
+			__func__);
+		goto fail;
+	}
+
+	rc = ion_phys(buf[0].client, buf[0].handle,
+		  (ion_phys_addr_t *)&buf[0].phys, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+			__func__, rc);
+		goto fail;
+	}
+
+	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle);
+	if (IS_ERR_OR_NULL((void *) buf[0].data)) {
+		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+		goto fail;
+	}
+	memset((void *)buf[0].data, 0, (bufsz * bufcnt));
+	if (!buf[0].data) {
+		pr_err("%s:invalid vaddr, iomap failed\n", __func__);
+		mutex_unlock(&ac->cmd_lock);
+		goto fail;
+	}
+
+	buf[0].used = dir ^ 1;
+	buf[0].size = bufsz;
+	buf[0].actual_size = bufsz;
+	cnt = 1;
+	while (cnt < bufcnt) {
+		if (bufsz > 0) {
+			buf[cnt].data =  buf[0].data + (cnt * bufsz);
+			buf[cnt].phys =  buf[0].phys + (cnt * bufsz);
+			if (!buf[cnt].data) {
+				pr_err("%s Buf alloc failed\n",
+							__func__);
+				mutex_unlock(&ac->cmd_lock);
+				goto fail;
+			}
+			buf[cnt].used = dir ^ 1;
+			buf[cnt].size = bufsz;
+			buf[cnt].actual_size = bufsz;
+			pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+				   (void *)buf[cnt].data,
+				   (void *)buf[cnt].phys,
+				   (void *)&buf[cnt].phys);
+		}
+		cnt++;
+	}
+	ac->port[dir].max_buf_cnt = cnt;
+	mutex_unlock(&ac->cmd_lock);
+	return 0;
+fail:
+	q6afe_audio_client_buf_free_contiguous(dir, ac);
+	return -EINVAL;
+}
 int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
 {
 	int ret = 0;
@@ -941,7 +1088,7 @@
 							mmap_region_cmd;
 	mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	mregion->hdr.pkt_size = sizeof(mregion);
+	mregion->hdr.pkt_size = cmd_size;
 	mregion->hdr.src_port = 0;
 	mregion->hdr.dest_port = 0;
 	mregion->hdr.token = 0;
@@ -961,13 +1108,15 @@
 	mregion_pl->shm_addr_msw = 0x00;
 	mregion_pl->mem_size_bytes = dma_buf_sz;
 
+	pr_debug("%s: dma_addr_p 0x%x , size %d\n", __func__,
+					dma_addr_p, dma_buf_sz);
 	atomic_set(&this_afe.state, 1);
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
 	if (ret < 0) {
 		pr_err("%s: AFE memory map cmd failed %d\n",
 		       __func__, ret);
 		ret = -EINVAL;
-		return ret;
+		goto fail_cmd;
 	}
 
 	ret = wait_event_timeout(this_afe.wait[index],
@@ -976,10 +1125,13 @@
 	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
-		return ret;
+		goto fail_cmd;
 	}
-
+	pr_debug("%s: mmap handle 0x%x\n", __func__, this_afe.mmap_handle);
 	return 0;
+fail_cmd:
+	kfree(mmap_region_cmd);
+	return ret;
 }
 
 int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz)
@@ -1047,6 +1199,60 @@
 	}
 	return 0;
 }
+int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
+			struct afe_audio_client *ac)
+{
+	struct afe_audio_port_data *port;
+	int cnt = 0;
+	mutex_lock(&ac->cmd_lock);
+	port = &ac->port[dir];
+	if (!port->buf) {
+		mutex_unlock(&ac->cmd_lock);
+		return 0;
+	}
+	cnt = port->max_buf_cnt - 1;
+
+	if (port->buf[0].data) {
+		ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
+		ion_free(port->buf[0].client, port->buf[0].handle);
+		ion_client_destroy(port->buf[0].client);
+		pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
+			__func__,
+			(void *)port->buf[0].data,
+			(void *)port->buf[0].phys,
+			(void *)&port->buf[0].phys,
+			(void *)port->buf[0].client,
+			(void *)port->buf[0].handle);
+	}
+
+	while (cnt >= 0) {
+		port->buf[cnt].data = NULL;
+		port->buf[cnt].phys = 0;
+		cnt--;
+	}
+	port->max_buf_cnt = 0;
+	kfree(port->buf);
+	port->buf = NULL;
+	mutex_unlock(&ac->cmd_lock);
+	return 0;
+}
+
+void q6afe_audio_client_free(struct afe_audio_client *ac)
+{
+	int loopcnt;
+	struct afe_audio_port_data *port;
+	if (!ac)
+		return;
+	for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+		port = &ac->port[loopcnt];
+		if (!port->buf)
+			continue;
+		pr_debug("%s:loopcnt = %d\n", __func__, loopcnt);
+		q6afe_audio_client_buf_free_contiguous(loopcnt, ac);
+	}
+	kfree(ac);
+	return;
+}
 
 int afe_cmd_memory_unmap(u32 mem_map_handle)
 {
@@ -1143,7 +1349,7 @@
 	int ret = 0;
 	struct afe_service_cmd_register_rt_port_driver rtproxy;
 
-	pr_debug("%s:\n", __func__);
+	pr_debug("%s: port_id: %d\n", __func__, port_id);
 
 	if (this_afe.apr == NULL) {
 		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
@@ -1206,9 +1412,6 @@
 			return ret;
 		}
 	}
-	index = q6audio_get_port_index(port_id);
-	if (q6audio_validate_port(port_id) < 0)
-		return -EINVAL;
 
 	if ((port_id == RT_PROXY_DAI_002_RX) ||
 		(port_id == RT_PROXY_DAI_001_TX))
@@ -1216,6 +1419,10 @@
 	else
 		return -EINVAL;
 
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0)
+		return -EINVAL;
+
 	rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 	rtproxy.hdr.pkt_size = sizeof(rtproxy);
@@ -1318,6 +1525,7 @@
 	afecmd_rd.buffer_address_lsw = (uint32_t)buf_addr_p;
 	afecmd_rd.buffer_address_msw = 0x00;
 	afecmd_rd.available_bytes = bytes;
+	afecmd_rd.mem_map_handle = mem_map_handle;
 
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
 	if (ret < 0) {
@@ -1665,11 +1873,11 @@
 	}
 	pr_debug("%s: port_id=%d\n", __func__, port_id);
 
+	port_id = q6audio_convert_virtual_to_portid(port_id);
 	index = q6audio_get_port_index(port_id);
 	if (q6audio_validate_port(port_id) < 0)
 		return -EINVAL;
 
-	port_id = q6audio_convert_virtual_to_portid(port_id);
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -1708,6 +1916,7 @@
 	atomic_set(&this_afe.state, 0);
 	atomic_set(&this_afe.status, 0);
 	this_afe.apr = NULL;
+	this_afe.mmap_handle = 0;
 	for (i = 0; i < AFE_MAX_PORTS; i++)
 		init_waitqueue_head(&this_afe.wait[i]);
 
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 9f98c1b..0dd6faf 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -819,6 +819,10 @@
 	}
 	sid = (data->token >> 8) & 0x0F;
 	ac = q6asm_get_audio_client(sid);
+	if (!ac) {
+		pr_debug("%s: session[%d] already freed\n", __func__, sid);
+		return 0;
+	}
 	pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
 		__func__, payload[0], payload[1], data->opcode, data->token,
 		data->payload_size, data->src_port, data->dest_port, sid, dir);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d2b333..4c6a5a4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -308,7 +308,7 @@
 {
 	static char buf[32];
 
-	if (type == PERF_TYPE_RAW) {
+	if (!pmu_name && type == PERF_TYPE_RAW) {
 		sprintf(buf, "raw 0x%" PRIx64, config);
 		return buf;
 	}
@@ -684,6 +684,7 @@
 {
 	struct perf_event_attr attr;
 	struct perf_pmu *pmu;
+	char *ev_name;
 
 	pmu = perf_pmu__find(name);
 	if (!pmu)
@@ -700,7 +701,9 @@
 	if (perf_pmu__config(pmu, &attr, head_config))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr, pmu->name);
+	ev_name = (char *) __event_name(attr.type, attr.config, pmu->name);
+
+	return add_event(list, idx, &attr, ev_name);
 }
 
 void parse_events_update_lists(struct list_head *list_event,