Merge "msm: kgsl: Don't spam the kernel log if qcom,step-pwrlevel isn't found"
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 17ff3f0..737e262 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -22,10 +22,24 @@
 	"arm,coresight-cti" for coresight cti devices,
 	"qcom,coresight-hwevent" for coresight hardware event devices
 	"arm,coresight-fuse" for coresight fuse device,
-- reg : physical base address and length of the register set(s) of the component
-- reg-names : names corresponding to each reg property value. The reg-names that
-	need to be used with corresponding compatible string for a coresight device
-	are:
+	"qcom,coresight-audio-etm" for coresight audio etm trace device,
+	"qcom,coresight-modem-etm" for coresight modem etm trace device,
+	"qcom,coresight-wcn-etm" for coresight wireless etm trace device,
+	"qcom,coresight-rpm-etm" for coresight rpm etm trace device
+- reg : physical base address and length of the register set(s) of the component.
+	Not required for the following compatible strings:
+	- "qcom,coresight-audio-etm",
+	- "qcom,coresight-modem-etm",
+	- "qcom,coresight-wcn-etm",
+	- "qcom,coresight-rpm-etm"
+- reg-names : names corresponding to each reg property value.
+	Not required for the following compatible strings:
+	- "qcom,coresight-audio-etm",
+	- "qcom,coresight-modem-etm",
+	- "qcom,coresight-wcn-etm",
+	- "qcom,coresight-rpm-etm"
+	The reg-names that need to be used with corresponding compatible string
+	for a coresight device are:
 	- for coresight tmc-etr or tmc-etf device:
 		compatible : should be "arm,coresight-tmc"
 		reg-names  : should be:
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index 3d7e5a2..e564cd5 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -3,6 +3,9 @@
 MDSS EDP is a edp driver which supports panels that are compatable with
 VESA EDP display interface specification.
 
+When configuring the optional properties for external backlight, one should also
+configure the gpio that drives the pwm to it.
+
 Required properties
 - compatible :				Must be "qcom,mdss-edp".
 - reg :						Offset and length of the register set for the
@@ -12,8 +15,6 @@
 - vdda-supply :				Phandle for vdd regulator device node.
 - gpio-panel-en	:			GPIO for supplying power to panel and backlight
 							driver.
-- qcom,panel-lpg-channel :		LPG channel for backlight.
-- qcom,panel-pwm-period :		PWM period in microseconds.
 - status :				A string that has to be set to "okay/ok" to enable
 						the driver. By default this property will be set to
 						"disable". Will be set to "ok/okay" status for
@@ -37,4 +38,8 @@
 		gpio-panel-hpd = <&msmgpio 102 0>;
 	};
 
+Optional properties
+- qcom,panel-lpg-channel :		LPG channel for backlight.
+- qcom,panel-pwm-period :		PWM period in microseconds.
+
 
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index bf30879..a4e61e8 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -107,6 +107,7 @@
 
 Optional properties:
 - vdd-cx-supply :	Phandle for vdd CX regulator device node.
+- batfet-supply :	Phandle for battery FET regulator device node.
 - qcom,vbif-settings :	Array with key-value pairs of constant VBIF register
 			settings used to setup MDSS QoS for optimum performance.
 			The key used should be offset from "vbif_phys" register
@@ -140,6 +141,11 @@
 				restricted for a source surface pipe. If this
 				property is not specified, no such restriction
 				would be applied.
+- qcom,mdss-pipe-rgb-fixed-mmb: Array of indexes describing fixed Memory Macro
+				Blocks (MMBs) for rgb pipes. First value denotes
+				total numbers of MMBs per pipe while values, if
+				any, following first one denotes indexes of MMBs
+				to that RGB pipe.
 
 Optional subnodes:
 Child nodes representing the frame buffer virtual devices.
@@ -179,6 +185,7 @@
 		interrupts = <0 72 0>;
 		vdd-supply = <&gdsc_mdss>;
 		vdd-cx-supply = <&pm8841_s2_corner>;
+		batfet-supply = <&pm8941_chg_batif>;
 		qcom,max-clk-rate = <320000000>;
 		qcom,vbif-settings = <0x0004 0x00000001>,
 				     <0x00D8 0x00000707>;
@@ -192,6 +199,10 @@
 		qcom,mdss-pipe-vig-fetch-id = <1 4 7>;
 		qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
 		qcom,mdss-pipe-dma-fetch-id = <10 13>;
+		qcom,mdss-pipe-rgb-fixed-mmb =	<2 0 1>,
+						<2 2 3>,
+						<2 4 5>,
+						<2 6 7>;
 		qcom,mdss-smp-data = <22 4096>;
 		qcom,mdss-rot-block-size = <64>;
 		qcom,mdss-smp-mb-per-pipe = <2>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
index 398e253..02186c9 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
@@ -23,30 +23,34 @@
  - focaltech,display-coords : display coordinates in pixels. It is a four
 				tuple consisting of min x, min y, max x and
 				max y values
- - focaltech,name	: name of the controller
  - focaltech,group-id	: group id of this device
+ - focaltech,num-max-touches	 : maximum number of touches supported
  - focaltech,hard-reset-delay-ms : hard reset delay in ms
  - focaltech,soft-reset-delay-ms : soft reset delay in ms
-
-Optional properties:
-
- - focaltech,panel-coords : panel coordinates for the chip in pixels.
-				It is a four tuple consisting of min x,
-				min y, max x and max y values
- - focaltech,i2c-pull-up : to specify pull up is required
- - focaltech,no-force-update : to specify force update is allowed
- - focaltech,button-map : button map of key codes. The number
-				of key codes depend on panel
- - focaltech,fw-name	: specify the firmware file name
- - focaltech,fw-delay-aa-ms : specify the "aa" delay in ms for firmware upgrade
- - focaltech,fw-delay-55-ms : specify the "55" delay in ms for firmware upgrade
+ - focaltech,fw-delay-aa-ms : specify the delay in ms after programming 0xaa
+				register for firmware upgrade
+ - focaltech,fw-delay-55-ms : specify the delay in ms after programming 0x55
+				register for firmware upgrade
  - focaltech,fw-upgrade-id1 : specify the upgrade id1 for firmware upgrade
  - focaltech,fw-upgrade-id2 : specify the upgrade id2 for firmware upgrade
  - focaltech,fw-delay-readid-ms : specify the read id delay in ms for firmware upgrade
  - focaltech,fw-delay-era-flsh-ms : specify the erase flash delay in ms for firmware upgrade
+
+Optional properties:
+
+ - focaltech,name	: name of the controller
+ - focaltech,i2c-pull-up : to specify pull up is required
+ - focaltech,no-force-update : to specify force update is allowed
+ - focaltech,button-map : button map of key codes. The number
+ - focaltech,fw-vkey-support	: specify if virtual keys are supported through firmware
+				of key codes depend on panel
  - focaltech,fw-auto-cal	: specify whether calibration is needed after firmware upgrade
  - focaltech,fw-vkey-support	: specify if virtual keys are supported through firmware
  - focaltech,ignore-id-check : specify ignore family-id check
+ - focaltech,panel-coords : panel coordinates for the chip in pixels.
+				It is a four tuple consisting of min x,
+				min y, max x and max y values
+ - focaltech,fw-name	: specify the firmware file name
 
 Example:
 	i2c@f9923000{
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
index d848baf..3b2c44c 100644
--- a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -10,6 +10,10 @@
 - qcom,flash-type : Should contain type flash device
     - 1 for LED flash
     - 2 for strobe flash
+    - 3 for simple led flash controlled by one gpio
+      This is a low cost led used for camera flash, the led is driven by
+      system power, and use a transistor controlled by external pin to
+      gate its on/off state.
 - qcom,flash-source : Should contain array of phandles to flash source nodes.
     - pm8941_flash0 pm8941_flash1
 
diff --git a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
index 893c033..c7821f5 100644
--- a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
@@ -10,7 +10,7 @@
 - cell-index: eeprom hardware core index
 - compatible :
     - "qcom,eeprom"
-- reg : offset and length of eeprom device registers.
+- reg : offset of eeprom device registers.
 - qcom,eeprom-name : should specify relevant names of the eeprom module
     library.
 - qcom,slave-addr : should specify the slave address of the eeprom.
@@ -29,7 +29,6 @@
     data type, delay in ms. size 0 stand for not used.
     - address type : 1 byte, 2 word.
     - data type : 1 byte, 2 word.
-- cam_vdig-supply : should contain regulator to be used for the digital vdd.
 - cam_vio-supply : should contain regulator to be used for the IO vdd.
 - qcom,cam-vreg-name : should specify the regulator name to be used for
     this eeprom.
@@ -57,6 +56,7 @@
 Optional properties:
 - qcom,pageen%d : number %d page enable reg size, start address, address type,
     data, data type, delay in ms. size 0 stand for not used.
+- cam_vdig-supply : should contain regulator to be used for the digital vdd.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 6f6f68d..d9376e9 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -39,26 +39,26 @@
   as "enum cp_mem_usage" in include/linux/msm_ion.h
 - qcom,has-ocmem: indicate the target has ocmem if this property exists
 - qcom,vidc-iommu-domains: node containing individual domain nodes, each with:
-	- a unique domain name for the domain node (e.g vidc,domain-ns)
-	- qcom,vidc-domain-phandle: phandle for the domain as defined in
-	  <target>-iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi)
-	- qcom,vidc-partition-buffer-types: bitmap of buffer types that can
-	  be mapped into each IOMMU domain partition.  There must be exactly
-	  one buffer bitmap per partition in the domain, with order of the
-	  bitmaps to be the same as the order of the respective partitions.
-	- Buffer types are defined as the following:
-	  input = 0x1
-	  output = 0x2
-	  output2 = 0x2
-	  extradata input = 0x4
-	  extradata output = 0x8
-	  extradata output2 = 0x8
-	  internal scratch = 0x10
-	  internal scratch1 = 0x20
-	  internal scratch2 = 0x40
-	  internal persist = 0x80
-	  internal persist1 = 0x100
-	  internal cmd queue = 0x200
+        - a unique domain name for the domain node (e.g vidc,domain-ns)
+        - qcom,vidc-domain-phandle: phandle for the domain as defined in
+          <target>-iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi)
+        - qcom,vidc-partition-buffer-types: bitmap of buffer types that can
+          be mapped into each IOMMU domain partition.  There must be exactly
+          one buffer bitmap per partition in the domain, with order of the
+          bitmaps to be the same as the order of the respective partitions.
+        - Buffer types are defined as the following:
+          input = 0x1
+          output = 0x2
+          output2 = 0x4
+          extradata input = 0x8
+          extradata output = 0x10
+          extradata output2 = 0x20
+          internal scratch = 0x40
+          internal scratch1 = 0x80
+          internal scratch2 = 0x100
+          internal persist = 0x200
+          internal persist1 = 0x400
+          internal cmd queue = 0x800
 
 Example:
 
@@ -95,14 +95,14 @@
 		qcom,vidc-iommu-domains {
 			qcom,domain-ns {
 				qcom,vidc-domain-phandle = <&venus_domain_ns>;
-				qcom,vidc-partition-buffer-types = <0x1ff>,
-							<0x200>;
+				qcom,vidc-partition-buffer-types = <0x7ff>,
+							<0x800>;
 			};
 
 			qcom,domain-cp {
 				qcom,vidc-domain-phandle = <&venus_domain_cp>;
-				qcom,vidc-partition-buffer-types = <0x2>,
-							<0x1f1>;
+				qcom,vidc-partition-buffer-types = <0x6>,
+							<0x7c1>;
 			};
 		};
 	};
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 3095b0a..83237f9 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -56,6 +56,7 @@
 				0 = Not supported
 				1 = Supported
 				This property is set to '0' if not specified.
+- qcom,use-bark			Specify if this pon type needs to handle bark irq
 - qcom,s1-timer			The debounce timer for the BARK interrupt for
 				that reset source. Value is specified in ms.
 				Supported values are -
@@ -106,6 +107,7 @@
 			qcom,s2-timer = <2000>;
 			qcom,s2-type = <1>;
 			linux,code = <114>;
+			qcom,use-bark;
 		};
 
 		qcom,pon_3 {
@@ -115,5 +117,6 @@
 			qcom,s2-timer = <2000>;
 			qcom,s2-type = <7>;
 			qcom,pull-up = <1>;
+			qcom,use-bark;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 53e912a..a7a646d 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -56,6 +56,8 @@
 		TX fifo allocation in bytes
 - qcom,dwc-usb3-msm-qdss-tx-fifo-size: If present, represent RAM size available
 		for TX fifo allocation in QDSS composition
+- qcom,dwc-ssphy-deemphasis-value: This property if present represents ss phy
+  deemphasis value to be used for overriding into SSPHY register.
 
 Sub nodes:
 - Sub node for "DWC3- USB3 controller".
@@ -82,6 +84,7 @@
 		qcom,dwc_usb3-adc_tm = <&pm8941_adc_tm>;
 		qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
 		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
+		qcom,dwc-ssphy-deemphasis-value = <26>;
 
 		qcom,msm_bus,name = "usb3";
 		qcom,msm_bus,num_cases = <2>;
diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 9f16c51..211831d 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -84,6 +84,8 @@
 HEALTH - represents health of the battery, values corresponds to
 POWER_SUPPLY_HEALTH_*, defined in battery.h.
 
+VOLTAGE_OCV - open circuit voltage of the battery.
+
 VOLTAGE_MAX_DESIGN, VOLTAGE_MIN_DESIGN - design values for maximal and
 minimal power supply voltages. Maximal/minimal means values of voltages
 when battery considered "full"/"empty" at normal conditions. Yes, there is
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index adcf168..9468df5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1853,13 +1853,36 @@
 config ENABLE_DMM
 	def_bool n
 
+choice
+	prompt "Virtual Memory Reclaim"
+	default NO_VM_RECLAIM
+	help
+	  Select the method of reclaiming virtual memory
+
 config DONT_MAP_HOLE_AFTER_MEMBANK0
-	def_bool n
-	depends on ENABLE_VMALLOC_SAVING=n
+	bool "Map around the largest hole"
+	help
+	  Do not map the memory belonging to the largest hole
+	  into the virtual space. This results in more lowmem.
+	  If multiple holes are present, only the largest hole
+	  in the first 256MB of memory is not mapped.
 
 config ENABLE_VMALLOC_SAVING
-	def_bool n
-	depends on DONT_MAP_HOLE_AFTER_MEMBANK0=n
+	bool "Reclaim memory for each subsystem"
+	help
+	  Enable this config to reclaim the virtual space belonging
+	  to any subsystem which is expected to have a lifetime of
+	  the entire system. This feature allows lowmem to be non-
+	  contiguous.
+
+config NO_VM_RECLAIM
+	bool "Do not reclaim memory"
+	help
+	  Do not reclaim any memory. This might result in less lowmem
+	  and wasting virtual memory space which could otherwise be
+	  reclaimed by using any of the other two config options.
+
+endchoice
 
 config HOLES_IN_ZONE
 	def_bool n
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 60bb518..824b0ab 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -23,9 +23,12 @@
 		status = "ok";
 	};
 
-	qcom,mdss_dsi_sharp_qhd_video {
-		status = "ok";
-		qcom,cont-splash-enabled;
+	qcom,mdss_dsi@fd922800 {
+		qcom,dsi-pref-prim-pan = <&dsi_sharp_qhd_vid>;
+	};
+
+	qcom,mdss_mdp@fd900000 {
+		qcom,mdss-pref-prim-intf = "dsi";
 	};
 
 	qcom,hdmi_tx@fd922100 {
@@ -501,13 +504,6 @@
 	};
 
 	gpio@e300 { /* GPIO 36 */
-		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 = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
-		qcom,src-sel = <3>; /* QPNP_PIN_SEL_FUNC_2 */
-		qcom,master-en = <1>;
 	};
 };
 
@@ -670,3 +666,7 @@
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 	status = "ok";
 };
+
+&dsi_sharp_qhd_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
new file mode 100755
index 0000000..7e63014
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -0,0 +1,135 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_hx8389b_qhd_vid: qcom,mdss_dsi_hx8389b_qhd_video {
+		qcom,mdss-dsi-panel-name = "HX8389b qhd video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <540>;
+		qcom,mdss-dsi-panel-height = <960>;
+		qcom,mdss-dsi-h-front-porch = <48>;
+		qcom,mdss-dsi-h-back-porch = <96>;
+		qcom,mdss-dsi-h-pulse-width = <96>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-front-porch = <9>;
+		qcom,mdss-dsi-v-pulse-width = <3>;
+		qcom,mdss-dsi-v-back-porch = <13>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				39 01 00 00 00 00 04
+					B9 FF 83 89
+				39 01 00 00 00 00 08
+					BA 41 93 00
+					16 A4 10 18
+				23 01 00 00 00 00 02
+					C6 08
+				39 01 00 00 00 00 03
+					BC 02 00
+				23 01 00 00 00 00 02
+					CC 02
+				39 01 00 00 00 00 14
+					B1 00 00 07
+					E8 50 10 11
+					98 f8 21 29
+					27 27 43 01
+					58 F0 00 E6
+				39 01 00 00 00 00 08
+					B2 00 00 78
+					0C 07 3F 80
+				39 01 00 00 00 00 18
+					b4 82 08 00
+					32 10 04 32
+					10 00 32 10
+					00 37 0a 40
+					08 37 0a 40
+					14 46 50 0a
+				39 01 00 00 00 00 39
+					d5 00 00 00
+					00 01 00 00
+					00 60 00 99
+					88 AA BB 88
+					23 88 01 88
+					67 88 45 01
+					23 88 88 88
+					88 88 88 99
+					BB AA 88 54
+					88 76 88 10
+					88 32 32 10
+					88 88 88 88
+					88 00 04 00
+					00 00 00 00
+					00
+				39 01 00 00 00 00 03
+					CB 07 07
+				39 01 00 00 00 00 05
+					BB 00 00 FF
+					80
+				39 01 00 00 00 00 04
+					DE 05 58 10
+				39 01 00 00 00 00 05
+					B6 00 8A 00
+					8A
+				39 01 00 00 00 00 23
+					E0 01 08 0C
+					1F 25 36 12
+					35 05 09 0D
+					10 11 0F 0F
+					1C 1D 01 08
+					0C 1F 25 36
+					12 35 05 09
+					0D 10 11 0F
+					0F 1C 1D
+				05 01 00 00 96 00 02
+					11 00
+				05 01 00 00 96 00 02
+					29 00
+		];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
new file mode 100644
index 0000000..1b64cf7
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
@@ -0,0 +1,72 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_jdi_1080_vid: qcom,mdss_dsi_jdi_1080p_video {
+		qcom,mdss-dsi-panel-name = "jdi 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <3>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 55 00
+			15 01 00 00 00 00 02 53 2C
+			15 01 00 00 00 00 02 35 00
+			05 01 00 00 78 00 02 29 00
+			05 01 00 00 78 00 02 11 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 02 00 02 28 00
+				 05 01 00 00 79 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [e1 37 25 00 67 6b 2a 3a 59 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = <0x04>;
+		qcom,mdss-dsi-mdp-trigger = <0x0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 5e0abea..f2ed8b5 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -50,6 +50,10 @@
 				qcom,pon-type = <1>;
 				qcom,pull-up = <1>;
 				linux,code = <114>;
+				qcom,s1-timer = <6720>;
+				qcom,s2-timer = <2000>;
+				qcom,s2-type = <7>;
+				qcom,support-reset = <1>;
 			};
 
 			qcom,pon_3 {
@@ -59,6 +63,7 @@
 				qcom,s1-timer = <6720>;
 				qcom,s2-timer = <2000>;
 				qcom,s2-type = <7>;
+				qcom,use-bark;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 8a239cc..c4de04c 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -69,6 +69,7 @@
 			qcom,s2-timer = <2000>;
 			qcom,s2-type = <1>;
 			linux,code = <114>;
+			qcom,use-bark;
 		};
 
 		qcom,pon_3 {
@@ -78,6 +79,7 @@
 			qcom,s2-timer = <2000>;
 			qcom,s2-type = <7>;
 			qcom,pull-up = <1>;
+			qcom,use-bark;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index ec3f248..feef9d5 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -215,12 +215,56 @@
 		qcom,round-robin;
 	};
 
+	audio_etm0 {
+		compatible = "qcom,coresight-audio-etm";
+
+		coresight-id = <14>;
+		coresight-name = "coresight-audio-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <2>;
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-modem-etm";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-modem-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <1>;
+	};
+
+	wcn_etm0 {
+		compatible = "qcom,coresight-wcn-etm";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-wcn-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <2>;
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-rpm-etm";
+
+		coresight-id = <17>;
+		coresight-name = "coresight-rpm-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <0>;
+	};
+
 	csr: csr@fc302000 {
 		compatible = "qcom,coresight-csr";
 		reg = <0xfc302000 0x1000>;
 		reg-names = "csr-base";
 
-		coresight-id = <14>;
+		coresight-id = <18>;
 		coresight-name = "coresight-csr";
 		coresight-nr-inports = <0>;
 
@@ -232,7 +276,7 @@
 		reg = <0xfc308000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <15>;
+		coresight-id = <19>;
 		coresight-name = "coresight-cti0";
 		coresight-nr-inports = <0>;
 	};
@@ -242,7 +286,7 @@
 		reg = <0xfc309000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <16>;
+		coresight-id = <20>;
 		coresight-name = "coresight-cti1";
 		coresight-nr-inports = <0>;
 	};
@@ -252,7 +296,7 @@
 		reg = <0xfc30a000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <17>;
+		coresight-id = <21>;
 		coresight-name = "coresight-cti2";
 		coresight-nr-inports = <0>;
 	};
@@ -262,7 +306,7 @@
 		reg = <0xfc30b000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <18>;
+		coresight-id = <22>;
 		coresight-name = "coresight-cti3";
 		coresight-nr-inports = <0>;
 	};
@@ -272,7 +316,7 @@
 		reg = <0xfc30c000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <19>;
+		coresight-id = <23>;
 		coresight-name = "coresight-cti4";
 		coresight-nr-inports = <0>;
 	};
@@ -282,7 +326,7 @@
 		reg = <0xfc30d000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <20>;
+		coresight-id = <24>;
 		coresight-name = "coresight-cti5";
 		coresight-nr-inports = <0>;
 	};
@@ -292,7 +336,7 @@
 		reg = <0xfc30e000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <21>;
+		coresight-id = <25>;
 		coresight-name = "coresight-cti6";
 		coresight-nr-inports = <0>;
 	};
@@ -302,7 +346,7 @@
 		reg = <0xfc30f000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <22>;
+		coresight-id = <26>;
 		coresight-name = "coresight-cti7";
 		coresight-nr-inports = <0>;
 	};
@@ -312,7 +356,7 @@
 		reg = <0xfc310000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <23>;
+		coresight-id = <27>;
 		coresight-name = "coresight-cti8";
 		coresight-nr-inports = <0>;
 	};
@@ -322,7 +366,7 @@
 		reg = <0xfc340000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <24>;
+		coresight-id = <28>;
 		coresight-name = "coresight-cti-l2";
 		coresight-nr-inports = <0>;
 	};
@@ -332,7 +376,7 @@
 		reg = <0xfc341000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <25>;
+		coresight-id = <29>;
 		coresight-name = "coresight-cti-cpu0";
 		coresight-nr-inports = <0>;
 	};
@@ -342,7 +386,7 @@
 		reg = <0xfc342000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <26>;
+		coresight-id = <30>;
 		coresight-name = "coresight-cti-cpu1";
 		coresight-nr-inports = <0>;
 	};
@@ -352,7 +396,7 @@
 		reg = <0xfc343000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <27>;
+		coresight-id = <31>;
 		coresight-name = "coresight-cti-cpu2";
 		coresight-nr-inports = <0>;
 	};
@@ -362,11 +406,61 @@
 		reg = <0xfc344000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <28>;
+		coresight-id = <32>;
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
 
+	cti_video_cpu0: cti@fc348000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc348000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <33>;
+		coresight-name = "coresight-cti-video-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_wcn_cpu0: cti@fc34d000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc34d000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <34>;
+		coresight-name = "coresight-cti-wcn-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_modem_cpu0: cti@fc350000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc350000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <35>;
+		coresight-name = "coresight-cti-modem-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_audio_cpu0: cti@fc354000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc354000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <36>;
+		coresight-name = "coresight-cti-audio-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_rpm_cpu0: cti@fc358000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc358000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <37>;
+		coresight-name = "coresight-cti-rpm-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
 	hwevent: hwevent@fd828018 {
 		compatible = "qcom,coresight-hwevent";
 		reg = <0xfd828018 0x80>,
@@ -375,7 +469,7 @@
 		      <0xfc401600 0x80>;
 		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
 
-		coresight-id = <29>;
+		coresight-id = <38>;
 		coresight-name = "coresight-hwevent";
 		coresight-nr-inports = <0>;
 
@@ -387,7 +481,7 @@
 		reg = <0xfc4be024 0x8>;
 		reg-names = "fuse-base";
 
-		coresight-id = <30>;
+		coresight-id = <39>;
 		coresight-name = "coresight-fuse";
 		coresight-nr-inports = <0>;
 	};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index dbd2031..a4bd8fd 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -497,6 +497,7 @@
 
 &mdss_mdp {
 	qcom,mdss-pref-prim-intf = "dsi";
+	batfet-supply = <&pm8226_chg_batif>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 701a3ef..eac0bb6 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -40,6 +40,7 @@
 			interrupts = <17 0x2>;
 			vdd-supply = <&pm8226_l19>;
 			vcc_i2c-supply = <&pm8226_lvs1>;
+			focaltech,name = "ft5x06";
 			focaltech,family-id = <0x55>;
 			focaltech,reset-gpio = <&msmgpio 16 0x00>;
 			focaltech,irq-gpio = <&msmgpio 17 0x00>;
@@ -48,6 +49,17 @@
 			focaltech,button-map= <139 102 158>;
 			focaltech,no-force-update;
 			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay-ms = <20>;
+			focaltech,soft-reset-delay-ms = <150>;
+			focaltech,num-max-touches = <5>;
+			focaltech,fw-name = "ft_8226_qrd_1080p_fw.bin";
+			focaltech,fw-delay-aa-ms = <50>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x03>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
 		};
 	};
 
@@ -482,6 +494,7 @@
 
 &mdss_mdp {
 	qcom,mdss-pref-prim-intf = "dsi";
+	batfet-supply = <&pm8226_chg_batif>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts
new file mode 100644
index 0000000..4b6a1da
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts
@@ -0,0 +1,29 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "msm8226-v2.dtsi"
+/include/ "msm8226-qrd.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8226v2 QRD PVT";
+	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+	qcom,board-id = <0x3000b 0>;
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35590_720_vid>;
+};
+
+&dsi_nt35590_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 8958984..151b508 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -189,14 +189,14 @@
 		qcom,vidc-iommu-domains {
 			qcom,domain-ns {
 				qcom,vidc-domain-phandle = <&venus_domain_ns>;
-				qcom,vidc-partition-buffer-types = <0x1ff>,
-							<0x200>;
+				qcom,vidc-partition-buffer-types = <0x7ff>,
+							<0x800>;
 			};
 
 			qcom,domain-cp {
 				qcom,vidc-domain-phandle = <&venus_domain_cp>;
-				qcom,vidc-partition-buffer-types = <0x2>,
-							<0x1f1>;
+				qcom,vidc-partition-buffer-types = <0x6>,
+							<0x7c1>;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 452cc2f..9920f77 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -162,8 +162,9 @@
 		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
 		qcom,cdc-vdd-mic-bias-current = <25000>;
 
+		qcom,cdc-micbias-ldoh-v = <0x3>;
 		qcom,cdc-micbias-cfilt-sel = <0x0>;
-		qcom,cdc-micbias-cfilt-mv = <1800000>;
+		qcom,cdc-micbias-cfilt-mv = <2700>;
 		qcom,cdc-mclk-clk-rate = <12288000>;
 
 		qcom,cdc-static-supplies = "cdc-vdda-h",
@@ -245,7 +246,6 @@
 
 	vdd-io-supply = <&pm8110_l6>;
 	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 1800000>;
 	qcom,vdd-io-current-level = <200 60000>;
 
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 78a4b5a..ca4f721 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -205,12 +205,56 @@
 		qcom,round-robin;
 	};
 
+	audio_etm0 {
+		compatible = "qcom,coresight-audio-etm";
+
+		coresight-id = <13>;
+		coresight-name = "coresight-audio-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <2>;
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-modem-etm";
+
+		coresight-id = <14>;
+		coresight-name = "coresight-modem-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <1>;
+	};
+
+	wcn_etm0 {
+		compatible = "qcom,coresight-wcn-etm";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-wcn-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <0>;
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-rpm-etm";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-rpm-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <0>;
+	};
+
 	csr: csr@fc301000 {
 		compatible = "qcom,coresight-csr";
 		reg = <0xfc301000 0x1000>;
 		reg-names = "csr-base";
 
-		coresight-id = <13>;
+		coresight-id = <17>;
 		coresight-name = "coresight-csr";
 		coresight-nr-inports = <0>;
 
@@ -222,7 +266,7 @@
 		reg = <0xfc310000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <14>;
+		coresight-id = <18>;
 		coresight-name = "coresight-cti0";
 		coresight-nr-inports = <0>;
 	};
@@ -232,7 +276,7 @@
 		reg = <0xfc311000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <15>;
+		coresight-id = <19>;
 		coresight-name = "coresight-cti1";
 		coresight-nr-inports = <0>;
 	};
@@ -242,7 +286,7 @@
 		reg = <0xfc312000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <16>;
+		coresight-id = <20>;
 		coresight-name = "coresight-cti2";
 		coresight-nr-inports = <0>;
 	};
@@ -252,7 +296,7 @@
 		reg = <0xfc313000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <17>;
+		coresight-id = <21>;
 		coresight-name = "coresight-cti3";
 		coresight-nr-inports = <0>;
 	};
@@ -262,7 +306,7 @@
 		reg = <0xfc314000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <18>;
+		coresight-id = <22>;
 		coresight-name = "coresight-cti4";
 		coresight-nr-inports = <0>;
 	};
@@ -272,7 +316,7 @@
 		reg = <0xfc315000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <19>;
+		coresight-id = <23>;
 		coresight-name = "coresight-cti5";
 		coresight-nr-inports = <0>;
 	};
@@ -282,7 +326,7 @@
 		reg = <0xfc316000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <20>;
+		coresight-id = <24>;
 		coresight-name = "coresight-cti6";
 		coresight-nr-inports = <0>;
 	};
@@ -292,7 +336,7 @@
 		reg = <0xfc317000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <21>;
+		coresight-id = <25>;
 		coresight-name = "coresight-cti7";
 		coresight-nr-inports = <0>;
 	};
@@ -302,7 +346,7 @@
 		reg = <0xfc318000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <22>;
+		coresight-id = <26>;
 		coresight-name = "coresight-cti8";
 		coresight-nr-inports = <0>;
 	};
@@ -312,7 +356,7 @@
 		reg = <0xfc351000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <23>;
+		coresight-id = <27>;
 		coresight-name = "coresight-cti-cpu0";
 		coresight-nr-inports = <0>;
 	};
@@ -322,7 +366,7 @@
 		reg = <0xfc352000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <24>;
+		coresight-id = <28>;
 		coresight-name = "coresight-cti-cpu1";
 		coresight-nr-inports = <0>;
 	};
@@ -332,7 +376,7 @@
 		reg = <0xfc353000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <25>;
+		coresight-id = <29>;
 		coresight-name = "coresight-cti-cpu2";
 		coresight-nr-inports = <0>;
 	};
@@ -342,11 +386,51 @@
 		reg = <0xfc354000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <26>;
+		coresight-id = <30>;
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
 
+	cti_wcn_cpu0: cti@fc335000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc335000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <31>;
+		coresight-name = "coresight-cti-wcn-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_modem_cpu0: cti@fc338000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc338000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <32>;
+		coresight-name = "coresight-cti-modem-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_audio_cpu0: cti@fc33c000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc33c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <33>;
+		coresight-name = "coresight-cti-audio-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_rpm_cpu0: cti@fc360000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc360000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <34>;
+		coresight-name = "coresight-cti-rpm-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
 	hwevent: hwevent@fd820018 {
 		compatible = "qcom,coresight-hwevent";
 		reg = <0xfd820018 0x80>,
@@ -355,7 +439,7 @@
 		      <0xfc401600 0x80>;
 		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
 
-		coresight-id = <27>;
+		coresight-id = <35>;
 		coresight-name = "coresight-hwevent";
 		coresight-nr-inports = <0>;
 
@@ -367,7 +451,7 @@
 		reg = <0xfc4be024 0x8>;
 		reg-names = "fuse-base";
 
-		coresight-id = <28>;
+		coresight-id = <36>;
 		coresight-name = "coresight-fuse";
 		coresight-nr-inports = <0>;
 	};
diff --git a/arch/arm/boot/dts/msm8610-mdss-panels.dtsi b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
index 243d7e8..afc5459 100644
--- a/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
@@ -15,3 +15,4 @@
 /include/ "dsi-panel-nt35590-720p-video.dtsi"
 /include/ "dsi-panel-otm8018b-fwvga-video.dtsi"
 /include/ "dsi-panel-hx8379a-wvga-video.dtsi"
+/include/ "dsi-panel-hx8389b-qhd-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 8d0e201..0244b89 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -229,8 +229,9 @@
 		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
 		qcom,cdc-vdd-mic-bias-current = <25000>;
 
+		qcom,cdc-micbias-ldoh-v = <0x3>;
 		qcom,cdc-micbias-cfilt-sel = <0x0>;
-		qcom,cdc-micbias-cfilt-mv = <1800000>;
+		qcom,cdc-micbias-cfilt-mv = <2700>;
 		qcom,cdc-mclk-clk-rate = <12288000>;
 
 		qcom,cdc-static-supplies = "cdc-vdda-h",
@@ -312,7 +313,6 @@
 
 	vdd-io-supply = <&pm8110_l6>;
 	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 1800000>;
 	qcom,vdd-io-current-level = <200 60000>;
 
@@ -445,6 +445,7 @@
 
 &mdss_mdp {
 	qcom,mdss-pref-prim-intf = "dsi";
+	batfet-supply = <&pm8110_chg_batif>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 2fe6a34..08e9be5 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -13,6 +13,16 @@
 /include/ "msm8610-qrd.dtsi"
 
 &soc {
+	gpio-leds {
+		compatible = "gpio-leds";
+		status = "disabled";
+
+		gpio_flash: gpio-flash {
+			gpios = <&pm8110_gpios 1 0>;
+			label = "gpio-flash";
+			linux,default-trigger = "gpio_flash_trigger";
+		};
+	};
     sound {
         qcom,model = "msm8x10-skuab-snd-card";
 
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index 83d84c0..d578ef6 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -175,8 +175,9 @@
 		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
 		qcom,cdc-vdd-mic-bias-current = <25000>;
 
+		qcom,cdc-micbias-ldoh-v = <0x3>;
 		qcom,cdc-micbias-cfilt-sel = <0x0>;
-		qcom,cdc-micbias-cfilt-mv = <1800000>;
+		qcom,cdc-micbias-cfilt-mv = <2700>;
 		qcom,cdc-mclk-clk-rate = <12288000>;
 
 		qcom,cdc-static-supplies = "cdc-vdda-h",
@@ -367,3 +368,7 @@
 	qcom,android-usb-cdrom;
 	qcom,android-usb-internal-ums;
 };
+
+&mdss_mdp {
+	batfet-supply = <&pm8110_chg_batif>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index e560447..6296692 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -180,7 +180,6 @@
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
-			<0xff 63>,  /* wcd9xxx_irq */
 			<0xff 65>,  /* o_gc_sys_irq[0] */
 			<0xff 74>,  /* venus0_mmu_cirpt[1] */
 			<0xff 75>,  /* venus0_mmu_cirpt[0] */
diff --git a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
new file mode 100644
index 0000000..4a08f3f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
@@ -0,0 +1,35 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-qrd-skuab.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v1 QRD SKUAB DVT2";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <0x2000b 3>;
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8389b_qhd_vid>;
+};
+
+&dsi_hx8389b_qhd_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 72509c1..6c7f2f6 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -177,7 +177,6 @@
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
-			<0xff 63>,  /* wcd9xxx_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
new file mode 100644
index 0000000..4735554
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
@@ -0,0 +1,58 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd-skuab.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 QRD SKUAB DVT2";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <0x2000b 3>;
+};
+
+&soc {
+	gpio-leds {
+		status = "ok";
+	};
+};
+
+&pm8110_gpios {
+	gpio@c000 { /* GPIO 1 */
+		reg = <0xc000 0x100>;
+		qcom,pin-num = <1>;
+	};
+};
+
+&led_flash0 {
+	status = "ok";
+};
+
+&i2c {
+	qcom,camera@20 {
+		qcom,led-flash-src = <&led_flash0>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8389b_qhd_vid>;
+};
+
+&dsi_hx8389b_qhd_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index b0f9d62..f6ced20 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -271,7 +271,6 @@
 
 		vdd-io-supply = <&pm8110_l6>;
 		qcom,vdd-io-always-on;
-		qcom,vdd-io-lpm-sup;
 		qcom,vdd-io-voltage-level = <1800000 1800000>;
 		qcom,vdd-io-current-level = <9000 60000>;
 
diff --git a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
index b060abe..205e749 100644
--- a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
@@ -11,6 +11,17 @@
  * GNU General Public License for more details.
  */
 
+&soc {
+
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <3>;
+		qcom,flash-source = <&gpio_flash>;
+		qcom,torch-source = <&gpio_flash>;
+		status = "disabled";
+	};
+};
 &i2c {
 
 	qcom,camera@20 {
@@ -67,6 +78,7 @@
 		gpios = <&msmgpio 14 0>,
 				<&msmgpio 15 0>,
 				<&msmgpio 85 0>;
+		qcom,gpio-reset = <1>;
 		qcom,gpio-standby = <2>;
 		qcom,gpio-req-tbl-num = <0 1 2>;
 		qcom,gpio-req-tbl-flags = <1 0 0>;
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
index a85e048..9b812da 100644
--- a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -31,6 +31,122 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom2: qcom,eeprom@6b{
+		cell-index = <2>;
+		reg = <0x6b>;
+		qcom,eeprom-name = "ofilm_oty5f03";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <7>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <0 0x0 2 0 1 0>;
+		qcom,page2 = <1 0x3d85 2 0x00 1 1>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <0 0x0 2 0 1 0>;
+		qcom,page3 = <1 0x3d86 2 0x0f 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <16 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <0 0x0 2 0 1 0>;
+		qcom,page5 = <1 0x3d85 2 0x10 1 1>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <0 0x0 2 0 1 0>;
+		qcom,page6 = <1 0x3d86 2 0x1f 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <16 0x3d00 2 0 1 0>;
+
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vana-supply = <&pm8226_l19>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <1 0>;
+		qcom,cam-vreg-min-voltage = <0 2850000>;
+		qcom,cam-vreg-max-voltage = <0 2850000>;
+		qcom,cam-vreg-op-mode = <0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 28 0>,
+		        <&msmgpio 35 0>,
+		        <&msmgpio 21 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		        "CAM_RESET",
+		        "CAM_STANDBY",
+		        "CAM_VDIG";
+		qcom,cam-power-seq-type = "sensor_vreg",
+		        "sensor_vreg", "sensor_gpio",
+		        "sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vio", "cam_vana","sensor_gpio_vdig",
+		         "sensor_gpio_reset",
+		        "sensor_gpio_standby","sensor_cam_mclk" ;
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 10 10 10 5>;
+	};
+
+	eeprom3: qcom,eeprom@6c {
+		cell-index = <3>;
+		reg = <0x6c>;
+		qcom,eeprom-name = "sunny_q8v18a";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x20>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <4>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <0 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d88 2 0x7010 2 1>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <0 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d8A 2 0x70F4 2 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <228 0x7010 2 0 1 1>;
+
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig","cam_vana", "cam_vio";
+		qcom,cam-vreg-type = <0 1 2>;
+		qcom,cam-vreg-min-voltage = <1200000 2850000 0>;
+		qcom,cam-vreg-max-voltage = <1200000 2850000 0>;
+		qcom,cam-vreg-op-mode = <200000 80000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 37 0>,
+		        <&msmgpio 36 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		        "CAM_RESET1",
+		        "CAM_STANDBY";
+		qcom,cam-power-seq-type = "sensor_vreg","sensor_vreg",
+		        "sensor_vreg", "sensor_clk",
+		        "sensor_gpio", "sensor_gpio";
+		qcom,cam-power-seq-val = "cam_vdig","cam_vana",
+		        "cam_vio", "sensor_cam_mclk",
+		        "sensor_gpio_reset",
+		        "sensor_gpio_standby";
+		qcom,cam-power-seq-cfg-val = <1 1 1 24000000 1 1>;
+		qcom,cam-power-seq-delay = <1 1 1 5 5 10>;
+	};
+
 	qcom,camera@20 {
 		compatible = "ovti,ov8865";
 		reg = <0x20>;
@@ -39,6 +155,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom3>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov8865_q8v18a";
 		cam_vdig-supply = <&pm8226_l5>;
@@ -78,16 +195,16 @@
 		qcom,slave-id = <0x6c 0x300a 0x5648>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
+		qcom,eeprom-src = <&eeprom2>;
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "ov5648_oty5f03";
-		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
 		cam_vio-supply = <&pm8226_lvs1>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
-		qcom,cam-vreg-type = <0 1 0>;
-		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
-		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
-		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <1 0>;
+		qcom,cam-vreg-min-voltage = <0 2850000>;
+		qcom,cam-vreg-max-voltage = <0 2850000>;
+		qcom,cam-vreg-op-mode = <0 80000>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 26 0>,
 				<&msmgpio 28 0>,
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index c84dfe5..07eb311 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -11,6 +11,16 @@
  * GNU General Public License for more details.
  */
 
+&soc {
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+		qcom,torch-source = <&pm8941_torch>;
+	};
+};
+
 &cci {
 
 	actuator0: qcom,actuator@18 {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 02d2288..9d44bda 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -11,6 +11,15 @@
  * GNU General Public License for more details.
  */
 
+&soc {
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+	};
+};
+
 &cci {
 
 	actuator0: qcom,actuator@18 {
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 610f237..28799ab 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -176,14 +176,6 @@
 		vdd-supply = <&gdsc_vfe>;
 	};
 
-	led_flash0: qcom,camera-led-flash {
-		cell-index = <0>;
-		compatible = "qcom,camera-led-flash";
-		qcom,flash-type = <1>;
-		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
-		qcom,torch-source = <&pm8941_torch>;
-	};
-
 	cci: qcom,cci@fda0C000 {
 		cell-index = <0>;
 		compatible = "qcom,cci";
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index a809c2b..b7e64c3 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -219,12 +219,57 @@
 		qcom,round-robin;
 	};
 
+	audio_etm0 {
+		compatible = "qcom,coresight-audio-etm";
+
+		coresight-id = <14>;
+		coresight-name = "coresight-audio-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <2>;
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-modem-etm";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-modem-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <1>;
+	};
+
+	wcn_etm0 {
+		compatible = "qcom,coresight-wcn-etm";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-wcn-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <2>;
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-rpm-etm";
+
+		coresight-id = <17>;
+		coresight-name = "coresight-rpm-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <0>;
+	};
+
+
 	csr: csr@fc302000 {
 		compatible = "qcom,coresight-csr";
 		reg = <0xfc302000 0x1000>;
 		reg-names = "csr-base";
 
-		coresight-id = <14>;
+		coresight-id = <18>;
 		coresight-name = "coresight-csr";
 		coresight-nr-inports = <0>;
 
@@ -236,7 +281,7 @@
 		reg = <0xfc308000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <15>;
+		coresight-id = <19>;
 		coresight-name = "coresight-cti0";
 		coresight-nr-inports = <0>;
 	};
@@ -246,7 +291,7 @@
 		reg = <0xfc309000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <16>;
+		coresight-id = <20>;
 		coresight-name = "coresight-cti1";
 		coresight-nr-inports = <0>;
 	};
@@ -256,7 +301,7 @@
 		reg = <0xfc30a000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <17>;
+		coresight-id = <21>;
 		coresight-name = "coresight-cti2";
 		coresight-nr-inports = <0>;
 	};
@@ -266,7 +311,7 @@
 		reg = <0xfc30b000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <18>;
+		coresight-id = <22>;
 		coresight-name = "coresight-cti3";
 		coresight-nr-inports = <0>;
 	};
@@ -276,7 +321,7 @@
 		reg = <0xfc30c000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <19>;
+		coresight-id = <23>;
 		coresight-name = "coresight-cti4";
 		coresight-nr-inports = <0>;
 	};
@@ -286,7 +331,7 @@
 		reg = <0xfc30d000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <20>;
+		coresight-id = <24>;
 		coresight-name = "coresight-cti5";
 		coresight-nr-inports = <0>;
 	};
@@ -296,7 +341,7 @@
 		reg = <0xfc30e000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <21>;
+		coresight-id = <25>;
 		coresight-name = "coresight-cti6";
 		coresight-nr-inports = <0>;
 	};
@@ -306,7 +351,7 @@
 		reg = <0xfc30f000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <22>;
+		coresight-id = <26>;
 		coresight-name = "coresight-cti7";
 		coresight-nr-inports = <0>;
 	};
@@ -316,7 +361,7 @@
 		reg = <0xfc310000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <23>;
+		coresight-id = <27>;
 		coresight-name = "coresight-cti8";
 		coresight-nr-inports = <0>;
 	};
@@ -326,7 +371,7 @@
 		reg = <0xfc340000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <24>;
+		coresight-id = <28>;
 		coresight-name = "coresight-cti-l2";
 		coresight-nr-inports = <0>;
 	};
@@ -336,7 +381,7 @@
 		reg = <0xfc341000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <25>;
+		coresight-id = <29>;
 		coresight-name = "coresight-cti-cpu0";
 		coresight-nr-inports = <0>;
 	};
@@ -346,7 +391,7 @@
 		reg = <0xfc342000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <26>;
+		coresight-id = <30>;
 		coresight-name = "coresight-cti-cpu1";
 		coresight-nr-inports = <0>;
 	};
@@ -356,7 +401,7 @@
 		reg = <0xfc343000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <27>;
+		coresight-id = <31>;
 		coresight-name = "coresight-cti-cpu2";
 		coresight-nr-inports = <0>;
 	};
@@ -366,11 +411,61 @@
 		reg = <0xfc344000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <28>;
+		coresight-id = <32>;
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
 
+	cti_video_cpu0: cti@fc348000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc348000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <33>;
+		coresight-name = "coresight-cti-video-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_wcn_cpu0: cti@fc34d000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc34d000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <34>;
+		coresight-name = "coresight-cti-wcn-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_modem_cpu0: cti@fc350000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc350000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <35>;
+		coresight-name = "coresight-cti-modem-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_audio_cpu0: cti@fc354000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc354000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <36>;
+		coresight-name = "coresight-cti-audio-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_rpm_cpu0: cti@fc358000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc358000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <37>;
+		coresight-name = "coresight-cti-rpm-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
 	hwevent: hwevent@fdf30018 {
 		compatible = "qcom,coresight-hwevent";
 		reg = <0xfdf30018 0x80>,
@@ -379,7 +474,7 @@
 		      <0xfc401600 0x80>;
 		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
 
-		coresight-id = <29>;
+		coresight-id = <38>;
 		coresight-name = "coresight-hwevent";
 		coresight-nr-inports = <0>;
 
@@ -391,7 +486,7 @@
 		reg = <0xfc4be024 0x8>;
 		reg-names = "fuse-base";
 
-		coresight-id = <30>;
+		coresight-id = <39>;
 		coresight-name = "coresight-fuse";
 		coresight-nr-inports = <0>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index c112bea..d0ca01d 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -30,6 +30,7 @@
 
 	qcom,mdss_mdp@fd900000 {
 		qcom,mdss-pref-prim-intf = "dsi";
+		batfet-supply = <&pm8941_chg_batif>;
 	};
 
 	qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 67e1802..ba085a0 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -26,6 +26,8 @@
 
         qcom,mdss_mdp@fd900000 {
                 qcom,mdss-pref-prim-intf = "edp";
+		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
+		qcom,panel-pwm-period = <53>;
         };
 
 	i2c@f9967000 {
@@ -214,7 +216,7 @@
 					/* Object 6, Instance = 0 */
 					00 00 00 00 00 00
 					/* Object 38, Instance = 0 */
-					19 03 00 1E 05 0D 00 00 00 00
+					19 04 00 07 08 0D 00 00 00 00
 					00 00 00 00 00 00 00 00 00 00
 					00 00 00 00 00 00 00 00 00 00
 					00 00 00 00 00 00 00 00 00 00
@@ -240,7 +242,7 @@
 					00 00 00 00 00 00 00 00 00
 					/* Object 25, Instance = 0 */
 					00 00 54 6F F0 55 00 00 00 00
-					00 00 00 00 00
+					00 00 00 00 0C
 					/* Object 27, Instance = 0 */
 					00 00 00 00 00 00 00
 					/* Object 40, Instance = 0 */
diff --git a/arch/arm/boot/dts/msm8974-mdss-panels.dtsi b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
index 00fc779..d405bf8 100644
--- a/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
@@ -14,3 +14,4 @@
 /include/ "dsi-panel-toshiba-720p-video.dtsi"
 /include/ "dsi-panel-sharp-qhd-video.dtsi"
 /include/ "dsi-panel-generic-720p-cmd.dtsi"
+/include/ "dsi-panel-jdi-1080p-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 6d5000f..c866de7 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -187,9 +187,6 @@
 		reg-names = "edp_base", "mmss_cc_base";
 		vdda-supply = <&pm8941_l12>;
 		gpio-panel-en = <&msmgpio 58 0>;
-		gpio-panel-pwm = <&pm8941_gpios 36 0>;
-		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
-		qcom,panel-pwm-period = <53>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
 		gpio-panel-hpd = <&msmgpio 102 0>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index b88fbdc..f73bcdc 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -30,6 +30,7 @@
 
 	qcom,mdss_mdp@fd900000 {
 		qcom,mdss-pref-prim-intf = "dsi";
+		batfet-supply = <&pm8941_chg_batif>;
 	};
 
 	qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index f2f73e9..55e18f0 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -140,24 +140,24 @@
 					<0x42 0x2>,
 					<0x120 0x3>;
 	qcom,vidc-iommu-domains {
-                qcom,domain-ns {
-                        qcom,vidc-domain-phandle = <&venus_domain_ns>;
-                        qcom,vidc-partition-buffer-types = <0x1ff>,
-							<0x200>;
-                };
-                qcom,domain-sec-bs {
-                        qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
-                        qcom,vidc-partition-buffer-types = <0x91>;
-                };
-                qcom,domain-sec-px {
-                        qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
-                        qcom,vidc-partition-buffer-types = <0x42>;
-                };
-                qcom,domain-sec-np {
-                        qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
-                        qcom,vidc-partition-buffer-types = <0x120>;
-                };
-        };
+		qcom,domain-ns {
+			qcom,vidc-domain-phandle = <&venus_domain_ns>;
+			qcom,vidc-partition-buffer-types = <0x7ff>,
+							<0x800>;
+		};
+		qcom,domain-sec-bs {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
+			qcom,vidc-partition-buffer-types = <0x241>;
+		};
+		qcom,domain-sec-px {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
+			qcom,vidc-partition-buffer-types = <0x106>;
+		};
+		qcom,domain-sec-np {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
+			qcom,vidc-partition-buffer-types = <0x480>;
+		};
+	};
 
 };
 
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3057e6e..8079324 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -914,7 +914,7 @@
 		qcom,misc-ref = <&pm8941_misc>;
 		dwc_usb3-adc_tm = <&pm8941_adc_tm>;
 		qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
-		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
+		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <8192>;
 
 		qcom,msm-bus,name = "usb3";
 		qcom,msm-bus,num-cases = <2>;
@@ -1484,7 +1484,7 @@
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9304000>;
 			qcom,dst-bam-pipe-index = <2>;
-			qcom,data-fifo-offset = <0xf2000>;
+			qcom,data-fifo-offset = <0xf0000>;
 			qcom,data-fifo-size = <0x1800>;
 			qcom,descriptor-fifo-offset = <0xf4000>;
 			qcom,descriptor-fifo-size = <0x1400>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
index 746702b..dc438bb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
@@ -106,6 +106,7 @@
 	interrupt-map = <0x0 0 &intc 0 133 0
 			0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
 	interrupt-names = "hs_phy_irq", "pmic_id_irq";
+	qcom,dwc-ssphy-deemphasis-value = <26>;
 };
 
 /* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
index 26fdebb..d5c1143 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -92,7 +92,7 @@
 	vdd-supply = <&pma8084_l20>;
 	vdd-io-supply = <&pma8084_s4>;
 
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 384000000>;
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 384000000>;
 	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
 
 	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index c38c9e1..df00f8a 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
@@ -480,6 +480,7 @@
 		#size-cells = <1>;
 		ranges;
 		qcom,pfm-threshold = <76>;
+		qcom,use-phase-scaling-factor;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index f45d75e..bd58653 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -214,20 +214,20 @@
 	qcom,vidc-iommu-domains {
 		qcom,domain-ns {
 			qcom,vidc-domain-phandle = <&venus_domain_ns>;
-			qcom,vidc-partition-buffer-types = <0x1ff>,
-							<0x200>;
+			qcom,vidc-partition-buffer-types = <0x7ff>,
+							<0x800>;
 		};
 		qcom,domain-sec-bs {
 			qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
-			qcom,vidc-partition-buffer-types = <0x91>;
+			qcom,vidc-partition-buffer-types = <0x241>;
 		};
 		qcom,domain-sec-px {
 			qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
-			qcom,vidc-partition-buffer-types = <0x42>;
+			qcom,vidc-partition-buffer-types = <0x106>;
 		};
 		qcom,domain-sec-np {
 			qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
-			qcom,vidc-partition-buffer-types = <0x120>;
+			qcom,vidc-partition-buffer-types = <0x480>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 4880f96..05d5238 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -135,12 +135,45 @@
 		qcom,round-robin;
 	};
 
+	audio_etm0 {
+		compatible = "qcom,coresight-audio-etm";
+
+		coresight-id = <9>;
+		coresight-name = "coresight-audio-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <2>;
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-modem-etm";
+
+		coresight-id = <10>;
+		coresight-name = "coresight-modem-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <1>;
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-rpm-etm";
+
+		coresight-id = <11>;
+		coresight-name = "coresight-rpm-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <0>;
+	};
+
 	csr: csr@fc302000 {
 		compatible = "qcom,coresight-csr";
 		reg = <0xfc302000 0x1000>;
 		reg-names = "csr-base";
 
-		coresight-id = <9>;
+		coresight-id = <12>;
 		coresight-name = "coresight-csr";
 		coresight-nr-inports = <0>;
 
@@ -152,7 +185,7 @@
 		reg = <0xfc308000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <10>;
+		coresight-id = <13>;
 		coresight-name = "coresight-cti0";
 		coresight-nr-inports = <0>;
 	};
@@ -162,7 +195,7 @@
 		reg = <0xfc309000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <11>;
+		coresight-id = <14>;
 		coresight-name = "coresight-cti1";
 		coresight-nr-inports = <0>;
 	};
@@ -172,7 +205,7 @@
 		reg = <0xfc30a000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <12>;
+		coresight-id = <15>;
 		coresight-name = "coresight-cti2";
 		coresight-nr-inports = <0>;
 	};
@@ -182,7 +215,7 @@
 		reg = <0xfc30b000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <13>;
+		coresight-id = <16>;
 		coresight-name = "coresight-cti3";
 		coresight-nr-inports = <0>;
 	};
@@ -192,7 +225,7 @@
 		reg = <0xfc30c000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <14>;
+		coresight-id = <17>;
 		coresight-name = "coresight-cti4";
 		coresight-nr-inports = <0>;
 	};
@@ -202,7 +235,7 @@
 		reg = <0xfc30d000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <15>;
+		coresight-id = <18>;
 		coresight-name = "coresight-cti5";
 		coresight-nr-inports = <0>;
 	};
@@ -212,7 +245,7 @@
 		reg = <0xfc30e000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <16>;
+		coresight-id = <19>;
 		coresight-name = "coresight-cti6";
 		coresight-nr-inports = <0>;
 	};
@@ -222,7 +255,7 @@
 		reg = <0xfc30f000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <17>;
+		coresight-id = <20>;
 		coresight-name = "coresight-cti7";
 		coresight-nr-inports = <0>;
 	};
@@ -232,18 +265,48 @@
 		reg = <0xfc310000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <18>;
+		coresight-id = <21>;
 		coresight-name = "coresight-cti8";
 		coresight-nr-inports = <0>;
 	};
 
-	cti_cpu: cti@fc333000 {
+	cti_cpu0: cti@fc333000 {
 		compatible = "arm,coresight-cti";
 		reg = <0xfc333000 0x1000>;
 		reg-names = "cti-base";
 
-		coresight-id = <19>;
-		coresight-name = "coresight-cti-cpu";
+		coresight-id = <22>;
+		coresight-name = "coresight-cti-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_modem_cpu0: cti@fc350000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc350000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <23>;
+		coresight-name = "coresight-cti-modem-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_audio_cpu0: cti@fc354000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc354000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <24>;
+		coresight-name = "coresight-cti-audio-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_rpm_cpu0: cti@fc358000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc358000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <25>;
+		coresight-name = "coresight-cti-rpm-cpu0";
 		coresight-nr-inports = <0>;
 	};
 
@@ -254,7 +317,7 @@
 		      <0xfc401600 0x80>;
 		reg-names = "apcs-mux", "ppss-mux", "gcc-mux";
 
-		coresight-id = <20>;
+		coresight-id = <26>;
 		coresight-name = "coresight-hwevent";
 		coresight-nr-inports = <0>;
 	};
@@ -264,7 +327,7 @@
 		reg = <0xfc4be024 0x8>;
 		reg-names = "fuse-base";
 
-		coresight-id = <21>;
+		coresight-id = <27>;
 		coresight-name = "coresight-fuse";
 		coresight-nr-inports = <0>;
 	};
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 108907a..2f38ebf 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -242,6 +242,9 @@
 CONFIG_PPPOE=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_MPPE=y
 CONFIG_USB_USBNET=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
@@ -449,3 +452,4 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
+CONFIG_DEFAULT_ROW=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 6d50e8d..8ca54fd 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -244,6 +244,9 @@
 CONFIG_PPPOE=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_MPPE=y
 CONFIG_USB_USBNET=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
@@ -443,6 +446,10 @@
 CONFIG_CORESIGHT_STM=y
 CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_AUDIO_ETM=y
+CONFIG_CORESIGHT_MODEM_ETM=y
+CONFIG_CORESIGHT_WCN_ETM=y
+CONFIG_CORESIGHT_RPM_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
@@ -500,3 +507,4 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
+CONFIG_DEFAULT_ROW=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 325aba1..7ea1bd5 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -81,6 +81,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -349,6 +350,7 @@
 CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_GPIO=y
 CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
@@ -406,6 +408,9 @@
 CONFIG_PPP_DEFLATE=y
 CONFIG_PPP_BSDCOMP=y
 CONFIG_PPPOE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_MPPE=y
 CONFIG_N_HDLC=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_INPUT_KXTJ9=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2c5363d..8e6f5f9 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -82,6 +82,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -372,6 +373,7 @@
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_MSM_GPIO_FLASH=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_GPIO=y
 CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
@@ -401,6 +403,10 @@
 CONFIG_CORESIGHT_STM=y
 CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_AUDIO_ETM=y
+CONFIG_CORESIGHT_MODEM_ETM=y
+CONFIG_CORESIGHT_WCN_ETM=y
+CONFIG_CORESIGHT_RPM_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
@@ -456,6 +462,9 @@
 CONFIG_PPP_DEFLATE=y
 CONFIG_PPP_BSDCOMP=y
 CONFIG_PPPOE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_MPPE=y
 CONFIG_N_HDLC=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_INPUT_KXTJ9=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index b26a028..8f6f52f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -475,6 +475,10 @@
 CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
+CONFIG_CORESIGHT_AUDIO_ETM=y
+CONFIG_CORESIGHT_MODEM_ETM=y
+CONFIG_CORESIGHT_WCN_ETM=y
+CONFIG_CORESIGHT_RPM_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_BIF=y
 CONFIG_BIF_QPNP=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 3f34690..d6811df 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -295,6 +295,9 @@
 CONFIG_CORESIGHT_STM=y
 CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_AUDIO_ETM=y
+CONFIG_CORESIGHT_MODEM_ETM=y
+CONFIG_CORESIGHT_RPM_ETM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_EXT3_FS=y
 CONFIG_VFAT_FS=y
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 9e27592..92e4f18 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -357,7 +357,7 @@
 	.rating	= 400,
 	.read	= arch_counter_read,
 	.mask	= CLOCKSOURCE_MASK(56),
-	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
 };
 
 static u32 arch_counter_get_cntvct32(void)
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 3e488e3..60be20a 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -55,7 +55,7 @@
 		.hfpll_phys_base = 0xF908A000,
 		.l2cpmr_iaddr = 0x4501,
 		.sec_clk_sel = 2,
-		.vreg[VREG_CORE] = { "krait0",     1100000 },
+		.vreg[VREG_CORE] = { "krait0",     1120000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH },
 		.vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
@@ -64,7 +64,7 @@
 		.hfpll_phys_base = 0xF909A000,
 		.l2cpmr_iaddr = 0x5501,
 		.sec_clk_sel = 2,
-		.vreg[VREG_CORE] = { "krait1",     1100000 },
+		.vreg[VREG_CORE] = { "krait1",     1120000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH },
 		.vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
@@ -73,7 +73,7 @@
 		.hfpll_phys_base = 0xF90AA000,
 		.l2cpmr_iaddr = 0x6501,
 		.sec_clk_sel = 2,
-		.vreg[VREG_CORE] = { "krait2",     1100000 },
+		.vreg[VREG_CORE] = { "krait2",     1120000 },
 		.vreg[VREG_MEM]  = { "krait2_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait2_dig", LVL_HIGH },
 		.vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
@@ -82,7 +82,7 @@
 		.hfpll_phys_base = 0xF90BA000,
 		.l2cpmr_iaddr = 0x7501,
 		.sec_clk_sel = 2,
-		.vreg[VREG_CORE] = { "krait3",     1100000 },
+		.vreg[VREG_CORE] = { "krait3",     1120000 },
 		.vreg[VREG_MEM]  = { "krait3_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait3_dig", LVL_HIGH },
 		.vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
@@ -273,10 +273,10 @@
 	[10] = { { 1036800, HFPLL, 1,  54 }, LVL_NOM,   950000, 5 },
 	[11] = { { 1113600, HFPLL, 1,  58 }, LVL_HIGH, 1050000, 6 },
 	[12] = { { 1190400, HFPLL, 1,  62 }, LVL_HIGH, 1050000, 6 },
-	[13] = { { 1267200, HFPLL, 1,  66 }, LVL_HIGH, 1050000, 7 },
-	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 7 },
-	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 7 },
-	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 7 },
+	[13] = { { 1267200, HFPLL, 1,  66 }, LVL_HIGH, 1050000, 6 },
+	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 6 },
+	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 6 },
+	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 6 },
 	[17] = { { 1574400, HFPLL, 1,  82 }, LVL_HIGH, 1050000, 7 },
 	[18] = { { 1651200, HFPLL, 1,  86 }, LVL_HIGH, 1050000, 7 },
 	[19] = { { 1728000, HFPLL, 1,  90 }, LVL_HIGH, 1050000, 8 },
@@ -900,219 +900,226 @@
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1060000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 708 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs1[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  785000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  795000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  905000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  785000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  795000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  905000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1035000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 708 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs2[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  865000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  885000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  865000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  885000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1010000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 708 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs3[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  755000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  765000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  785000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  795000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  755000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  765000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  785000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  795000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  985000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 708 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  755000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  765000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  785000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  795000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  755000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  765000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  785000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  795000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  960000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 708 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs5[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  735000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  745000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  755000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  765000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  915000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  735000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  745000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  755000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  765000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  915000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  940000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 708 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p3g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 159 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  735000, 180 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  745000, 200 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  755000, 221 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  765000, 242 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 264 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  785000, 287 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  795000, 308 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  805000, 333 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  815000, 356 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 380 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  835000, 404 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 430 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 456 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 482 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  870000, 510 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 538 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  890000, 565 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 596 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 627 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 659 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  925000, 691 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  74 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  85 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 104 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 124 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 144 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 164 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  735000, 184 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  745000, 206 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  755000, 227 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  765000, 249 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 271 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  785000, 295 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  795000, 318 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  805000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  815000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 392 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  835000, 416 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 442 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 469 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 497 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  870000, 525 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 554 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  890000, 583 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 613 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 642 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  915000, 663 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 675 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  925000, 708 },
 	{ 0, { 0 } }
 };
 
@@ -1122,31 +1129,32 @@
 	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
 	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125 },
 	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  845000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  855000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  915000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  945000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1080000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1100000, 800 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  910000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  920000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  930000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  945000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  960000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  975000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  990000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1050000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1065000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1080000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1095000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1100000, 785 },
 	{ 0, { 0 } }
 };
 
@@ -1156,31 +1164,32 @@
 	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
 	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125 },
 	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  915000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  995000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1035000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1075000, 800 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  845000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  855000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  865000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  875000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  905000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  920000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  935000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  950000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  965000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  980000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  995000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1025000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1055000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1070000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1075000, 785 },
 	{ 0, { 0 } }
 };
 
@@ -1190,31 +1199,32 @@
 	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106 },
 	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125 },
 	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  830000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  850000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  880000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  910000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  970000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1030000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1050000, 800 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  880000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  895000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  955000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  970000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  985000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1000000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1030000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1045000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1050000, 785 },
 	{ 0, { 0 } }
 };
 
@@ -1224,65 +1234,67 @@
 	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106 },
 	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125 },
 	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  820000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  840000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  865000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  880000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  910000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  925000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  955000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  970000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  985000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1025000, 800 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  780000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  870000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  885000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  900000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  945000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  960000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  975000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  975000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1005000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1020000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1025000, 785 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p5g_pvs4[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  760000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  770000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  840000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  850000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  865000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  895000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  910000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  925000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  955000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  970000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  985000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1000000, 800 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  775000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  845000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  875000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  890000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  935000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  950000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  950000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  965000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  980000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  995000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1000000, 785 },
 	{ 0, { 0 } }
 };
 
@@ -1292,65 +1304,67 @@
 	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106 },
 	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125 },
 	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  760000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  770000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  800000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  810000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  820000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  830000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  840000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  850000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  860000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  870000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  885000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  900000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  930000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  945000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  960000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  975000, 800 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  750000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  760000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  770000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  780000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  790000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  800000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  810000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  820000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  835000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  850000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  865000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  880000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  910000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  925000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  925000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  940000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  955000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  970000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19),  975000, 785 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level pro_rev0_2p5g_pvs6[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  76 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  87 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 106 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 125 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 145 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 164 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  725000, 183 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  725000, 202 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  725000, 222 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  725000, 241 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  735000, 261 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  745000, 282 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  755000, 305 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  765000, 327 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  775000, 350 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  785000, 373 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  795000, 398 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  805000, 424 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  815000, 449 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  825000, 476 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  835000, 503 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  845000, 530 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  855000, 559 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  865000, 590 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  875000, 621 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  890000, 654 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  905000, 686 },
-	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  920000, 723 },
-	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  935000, 761 },
-	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  950000, 800 },
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 165 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 186 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 208 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 229 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 251 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 273 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  750000, 296 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  750000, 319 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  755000, 342 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  765000, 365 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  775000, 390 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  785000, 415 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  795000, 439 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  805000, 465 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  815000, 493 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  825000, 521 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  840000, 549 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  855000, 579 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  870000, 608 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  885000, 638 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  900000, 667 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  900000, 667 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  915000, 700 },
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  930000, 734 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  945000, 769 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19),  950000, 785 },
 	{ 0, { 0 } }
 };
 
@@ -1380,6 +1394,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1040000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1055000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1070000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1070000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1085000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1100000, 751 },
@@ -1414,6 +1429,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1060000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1090000, 751 },
@@ -1448,6 +1464,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1005000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1020000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1035000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1050000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1050000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1065000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1080000, 751 },
@@ -1482,6 +1499,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1010000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1025000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1040000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1040000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1055000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1070000, 751 },
@@ -1516,6 +1534,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  985000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1000000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1015000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1030000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1030000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1045000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 751 },
@@ -1550,6 +1569,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  975000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  990000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1005000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1020000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1035000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1050000, 751 },
@@ -1584,6 +1604,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  965000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1010000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1040000, 751 },
@@ -1618,6 +1639,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  955000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  970000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  985000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1000000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1000000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1030000, 751 },
@@ -1652,6 +1674,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  990000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  990000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1005000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1020000, 751 },
@@ -1686,6 +1709,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  935000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  950000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  965000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  980000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  980000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  995000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 751 },
@@ -1720,6 +1744,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  970000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  970000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  985000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1000000, 751 },
@@ -1754,6 +1779,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  915000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  930000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  945000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  960000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  990000, 751 },
@@ -1788,6 +1814,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  935000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  950000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  950000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  965000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  980000, 751 },
@@ -1822,6 +1849,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  895000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  910000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  925000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  940000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  955000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  970000, 751 },
@@ -1856,6 +1884,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  885000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  900000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  915000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  930000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  930000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  945000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  960000, 751 },
@@ -1890,6 +1919,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  875000, 588 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  890000, 617 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 649 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  920000, 682 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  920000, 682 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  935000, 716 },
 	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  950000, 751 },
@@ -1924,6 +1954,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1060000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1075000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1090000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1105000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1105000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1120000, 738 },
 	{ 0, { 0 } }
@@ -1955,6 +1986,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1065000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1080000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1095000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1095000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1110000, 738 },
 	{ 0, { 0 } }
@@ -1986,6 +2018,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1085000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 738 },
 	{ 0, { 0 } }
@@ -2017,6 +2050,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1030000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1045000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1060000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1075000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1075000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1090000, 738 },
 	{ 0, { 0 } }
@@ -2048,6 +2082,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1035000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1050000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1065000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1065000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1080000, 738 },
 	{ 0, { 0 } }
@@ -2079,6 +2114,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1010000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1025000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1040000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1055000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1055000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1070000, 738 },
 	{ 0, { 0 } }
@@ -2110,6 +2146,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1015000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1030000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1045000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1045000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1060000, 738 },
 	{ 0, { 0 } }
@@ -2141,6 +2178,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  990000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1035000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 738 },
 	{ 0, { 0 } }
@@ -2172,6 +2210,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  980000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  995000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1010000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1025000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1025000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 738 },
 	{ 0, { 0 } }
@@ -2203,6 +2242,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  985000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1015000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1015000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1030000, 738 },
 	{ 0, { 0 } }
@@ -2234,6 +2274,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  975000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  990000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19), 1005000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1005000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1020000, 738 },
 	{ 0, { 0 } }
@@ -2265,6 +2306,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  965000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  980000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  995000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  995000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1010000, 738 },
 	{ 0, { 0 } }
@@ -2296,6 +2338,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  940000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  955000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  985000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 738 },
 	{ 0, { 0 } }
@@ -2327,6 +2370,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  945000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  960000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  975000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  975000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 738 },
 	{ 0, { 0 } }
@@ -2358,6 +2402,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  920000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  965000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  965000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  980000, 738 },
 	{ 0, { 0 } }
@@ -2389,6 +2434,7 @@
 	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  910000, 604 },
 	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  925000, 636 },
 	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 669 },
+	{ 0, { 2150400, HFPLL, 1, 112 }, L2(19),  955000, 703 },
 	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  955000, 703 },
 	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  970000, 738 },
 	{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 993ce58..a883e39 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3217,6 +3217,11 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc348000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc358000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fd828018.hwevent"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
@@ -3251,6 +3256,11 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc348000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc358000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd828018.hwevent"),
 
 	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent"),
@@ -3371,6 +3381,7 @@
 	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
 
 	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 85a9f45..45a6b89 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -1351,8 +1351,6 @@
 	.cbcr_reg = LPASS_Q6_AXI_CBCR,
 	.has_sibling = 1,
 	.base = &virt_bases[GCC_BASE],
-	 /* FIXME: Remove this once simulation is fixed. */
-	.halt_check = DELAY,
 	.c = {
 		.dbg_name = "gcc_lpass_q6_axi_clk",
 		.ops = &clk_ops_branch,
@@ -1893,14 +1891,10 @@
 	.cbcr_reg = BIMC_GFX_CBCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
-	 /* FIXME: Remove this once simulation is fixed. */
-	.halt_check = DELAY,
 	.c = {
 		.dbg_name = "bimc_gfx_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(bimc_gfx_clk.c),
-		/* FIXME: Remove once kgsl votes on the depends clock. */
-		.depends = &gcc_bimc_smmu_clk.c,
 	},
 };
 
@@ -2267,8 +2261,6 @@
 static struct branch_clk mdp_axi_clk = {
 	.cbcr_reg = MDP_AXI_CBCR,
 	.base = &virt_bases[MMSS_BASE],
-	 /* FIXME: Remove this once simulation is fixed. */
-	.halt_check = DELAY,
 	.c = {
 		.parent = &mdp_axi_clk_src.c,
 		.dbg_name = "mdp_axi_clk",
@@ -2416,8 +2408,6 @@
 	.bcr_reg = VFE_AXI_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
-	 /* FIXME: Remove this once simulation is fixed. */
-	.halt_check = DELAY,
 	.c = {
 		.parent = &axi_clk_src.c,
 		.dbg_name = "vfe_axi_clk",
@@ -2831,6 +2821,10 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc352000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc353000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc335000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc338000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33c000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc360000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34c000.jtagmm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.jtagmm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.jtagmm"),
@@ -2865,6 +2859,10 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc352000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc353000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc335000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc338000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc360000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34c000.jtagmm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.jtagmm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.jtagmm"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 32a2617..03fcb25 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1545,6 +1545,24 @@
 	},
 };
 
+/* This table is for MSM8974Pro AC SDCC1 */
+static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk_ac[] = {
+	F(   144000,    cxo,  16,   3,  25),
+	F(   400000,    cxo,  12,   1,   4),
+	F( 20000000,  gpll0,  15,   1,   2),
+	F( 25000000,  gpll0,  12,   1,   2),
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F(192000000,  gpll4,   4,   0,   0),
+	F(384000000,  gpll4,   2,   0,   0),
+	F_END
+};
+
+/*
+ * This table is for:
+ * 1) SDCC[1-4] on MSM8974Pro AB, MSM8974 v2 and before
+ * 2) SDCC[2-4] on MSM8974Pro AC
+ */
 static struct clk_freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = {
 	F(   144000,    cxo,  16,   3,  25),
 	F(   400000,    cxo,  12,   1,   4),
@@ -1553,7 +1571,6 @@
 	F( 50000000,  gpll0,  12,   0,   0),
 	F(100000000,  gpll0,   6,   0,   0),
 	F(200000000,  gpll0,   3,   0,   0),
-	F(384000000,  gpll4,   2,   0,   0),
 	F_END
 };
 
@@ -5085,6 +5102,8 @@
 	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
+	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922e00.qcom,mdss_dsi"),
 	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"),
@@ -5444,6 +5463,11 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc348000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc358000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fdf30018.hwevent"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
@@ -5474,6 +5498,11 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc348000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc358000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fdf30018.hwevent"),
 
 	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fdf30018.hwevent"),
@@ -5777,6 +5806,7 @@
 	if (cpu_is_msm8974pro_ac()) {
 		sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
 		sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
+		sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_ac;
 	}
 
 	vfe0_clk_src.c.fmax[VDD_DIG_LOW] = 150000000;
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 3b07069..0b73ac9 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -1887,6 +1887,9 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc358000.cti"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "f9011038.hwevent"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
@@ -1909,6 +1912,9 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc358000.cti"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
 };
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index ddf747e..7c694a7 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -766,6 +766,8 @@
 		pdata = msm_bus_of_get_fab_data(pdev);
 		if (IS_ERR(pdata) || ZERO_OR_NULL_PTR(pdata)) {
 			pr_err("Null platform data\n");
+			kfree(fabric->info.node_info);
+			kfree(fabric);
 			return PTR_ERR(pdata);
 		}
 		msm_bus_board_init(pdata);
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 620ab5c..69df3ae 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -334,7 +334,7 @@
 		pr_err("Ignoring wcnss bite irq, restart in progress\n");
 		return IRQ_HANDLED;
 	}
-	wcnss_pronto_log_debug_regs();
+	wcnss_log_debug_regs_on_bite();
 
 	drv->restart_inprogress = true;
 	restart_wcnss(drv);
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index de15be5..322061d 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -494,7 +494,7 @@
 	if (!lpass_status) {
 		pr_err("%s: kobject create failed\n", __func__);
 		ret = -ENOMEM;
-		goto err_notif_modem;
+		goto err_create_kobj;
 	}
 
 	ret = sysfs_create_group(lpass_status, &attr_group);
@@ -507,6 +507,8 @@
 	return 0;
 err_kobj:
 	kobject_put(lpass_status);
+err_create_kobj:
+	subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
 err_notif_modem:
 	subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
 err_notif_wcnss:
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 00b0b3b..af21584 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -651,8 +651,11 @@
 {
 	int64_t time = 0;
 
-	if (msm_pm_use_sync_timer)
-		return sched_clock();
+	if (msm_pm_use_sync_timer) {
+		struct timespec ts;
+		getnstimeofday(&ts);
+		return timespec_to_ns(&ts);
+	}
 
 	time = msm_timer_get_sclk_time(period);
 	if (!time)
@@ -663,8 +666,12 @@
 
 static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
 {
-	if (msm_pm_use_sync_timer)
-		return sched_clock() - time;
+	if (msm_pm_use_sync_timer) {
+		struct timespec ts;
+		getnstimeofday(&ts);
+
+		return timespec_to_ns(&ts) - time;
+	}
 
 	if (time != 0) {
 		int64_t end_time = msm_timer_get_sclk_time(NULL);
@@ -1048,12 +1055,14 @@
 }
 EXPORT_SYMBOL(msm_pm_enable_retention);
 
+static int64_t suspend_time, suspend_period;
+static int collapsed;
+static int suspend_power_collapsed;
+
 static int msm_pm_enter(suspend_state_t state)
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
 	int i;
-	int64_t period = 0;
-	int64_t time = msm_pm_timer_enter_suspend(&period);
 	struct msm_pm_time_params time_param;
 
 	time_param.latency_us = -1;
@@ -1081,7 +1090,6 @@
 		int ret = -ENODEV;
 		uint32_t power;
 		uint32_t msm_pm_max_sleep_time = 0;
-		int collapsed = 0;
 
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: power collapse\n", __func__);
@@ -1115,11 +1123,7 @@
 			pr_err("%s: cannot find the lowest power limit\n",
 				__func__);
 		}
-		time = msm_pm_timer_exit_suspend(time, period);
-		if (collapsed)
-			msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
-		else
-			msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND, time);
+		suspend_power_collapsed = true;
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: standalone power collapse\n", __func__);
@@ -1149,6 +1153,7 @@
 
 static int msm_suspend_prepare(void)
 {
+	suspend_time = msm_pm_timer_enter_suspend(&suspend_period);
 	msm_mpm_suspend_prepare();
 	return 0;
 }
@@ -1156,6 +1161,16 @@
 static void msm_suspend_wake(void)
 {
 	msm_mpm_suspend_wake();
+	if (suspend_power_collapsed) {
+		suspend_time = msm_pm_timer_exit_suspend(suspend_time,
+				suspend_period);
+		if (collapsed)
+			msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
+		else
+			msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND,
+					suspend_time);
+		suspend_power_collapsed = false;
+	}
 }
 
 static const struct platform_suspend_ops msm_pm_ops = {
diff --git a/arch/arm/mach-msm/qdsp6v2/aac_in.c b/arch/arm/mach-msm/qdsp6v2/aac_in.c
index 5e959b5..865f6f2 100644
--- a/arch/arm/mach-msm/qdsp6v2/aac_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/aac_in.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -58,11 +58,33 @@
 			break;
 		}
 
-		rc = audio_in_buf_alloc(audio);
-		if (rc < 0) {
-			pr_err("%s:session id %d: buffer allocation failed\n",
-				__func__, audio->ac->session);
-			break;
+		if (audio->opened) {
+			rc = audio_in_buf_alloc(audio);
+			if (rc < 0) {
+				pr_err("%s:session id %d: buffer allocation failed\n",
+					 __func__, audio->ac->session);
+				break;
+			}
+		} else {
+			if(audio->feedback == NON_TUNNEL_MODE){
+				pr_debug("%s: starting in non_tunnel mode",__func__);
+				rc = q6asm_open_read_write(audio->ac, FORMAT_MPEG4_AAC,
+						FORMAT_LINEAR_PCM);
+				if (rc < 0) {
+					pr_err("%s:open read write failed\n", __func__);
+					break;
+				}
+			}
+			if(audio->feedback == TUNNEL_MODE){
+				pr_debug("%s: starting in tunnel mode",__func__);
+				rc = q6asm_open_read(audio->ac,FORMAT_MPEG4_AAC);
+
+				if (rc < 0) {
+					pr_err("%s:open read failed\n", __func__);
+					break;
+				}
+			}
+		audio->stopped = 0;
 		}
 
 		pr_debug("%s:sbr_ps_flag = %d, sbr_flag = %d\n", __func__,
@@ -125,6 +147,7 @@
 	case AUDIO_GET_AAC_ENC_CONFIG: {
 		struct msm_audio_aac_enc_config cfg;
 		struct msm_audio_aac_enc_config *enc_cfg;
+		memset(&cfg, 0, sizeof(cfg));
 		enc_cfg = audio->enc_cfg;
 		if (enc_cfg->channels == CH_MODE_MONO)
 			cfg.channels = 1;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
index 902e06d..544bf9c 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -36,7 +36,7 @@
 	}
 }
 #else
-static void config_debug_fs(struct q6audio_aio *)
+static void config_debug_fs(struct q6audio_aio *audio)
 {
 }
 #endif
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 5355de1..85af4a7 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -260,14 +260,16 @@
 		}
 		audio->str_cfg.buffer_size = cfg.buffer_size;
 		audio->str_cfg.buffer_count = cfg.buffer_count;
-		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+		if(audio->opened){
+			rc = q6asm_audio_client_buf_alloc(OUT,audio->ac,
 				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
 				audio->str_cfg.buffer_count);
-		if (rc < 0) {
+			if (rc < 0) {
 			pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
-					__func__, audio->ac->session, rc);
+				__func__, audio->ac->session, rc);
 			rc = -ENOMEM;
 			break;
+			}
 		}
 		audio->buf_alloc |= BUF_ALLOC_OUT;
 		rc = 0;
@@ -349,14 +351,16 @@
 		audio->pcm_cfg.buffer_size  = cfg.buffer_size;
 		audio->pcm_cfg.channel_count = cfg.channel_count;
 		audio->pcm_cfg.sample_rate = cfg.sample_rate;
-		rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
-			ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
-			audio->pcm_cfg.buffer_count);
-		if (rc < 0) {
-			pr_err("%s:session id %d: Buffer Alloc failed\n",
-				__func__, audio->ac->session);
-			rc = -ENOMEM;
-			break;
+		if(audio->opened && audio->feedback == NON_TUNNEL_MODE){
+			rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+				audio->pcm_cfg.buffer_count);
+			if(rc < 0){
+				pr_err("%s:session id %d: Buffer Alloc failed\n",
+						__func__,audio->ac->session);
+				rc = -ENOMEM;
+				break;
+			}
 		}
 		audio->buf_alloc |= BUF_ALLOC_IN;
 		rc = 0;
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index 266b759..601c42c 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -114,6 +114,7 @@
 
 static int scm_remap_error(int err)
 {
+	pr_err("scm_call failed with error code %d\n", err);
 	switch (err) {
 	case SCM_ERROR:
 		return -EIO;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 53bbe20..8af3890 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -32,6 +32,16 @@
 #include "boot_stats.h"
 
 #define BUILD_ID_LENGTH 32
+#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
+#define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128
+#define SMEM_IMAGE_VERSION_SIZE 4096
+#define SMEM_IMAGE_VERSION_NAME_SIZE 75
+#define SMEM_IMAGE_VERSION_NAME_OFFSET 3
+#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
+#define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75
+#define SMEM_IMAGE_VERSION_OEM_SIZE 32
+#define SMEM_IMAGE_VERSION_OEM_OFFSET 96
+#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
 
 enum {
 	HW_PLATFORM_UNKNOWN = 0,
@@ -421,6 +431,7 @@
 };
 
 static enum msm_cpu cur_cpu;
+static int current_image;
 
 static struct socinfo_v1 dummy_socinfo = {
 	.format = 1,
@@ -503,6 +514,11 @@
 		: 0;
 }
 
+static char *socinfo_get_image_version_base_address(void)
+{
+	return smem_alloc(SMEM_IMAGE_VERSION_TABLE, SMEM_IMAGE_VERSION_SIZE);
+}
+
 static uint32_t socinfo_get_format(void)
 {
 	return socinfo ? socinfo->v1.format : 0;
@@ -829,6 +845,107 @@
 			 socinfo_get_pmic_die_revision());
 }
 
+static ssize_t
+msm_get_image_version(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	char *string_address;
+
+	string_address = socinfo_get_image_version_base_address();
+	if (string_address == NULL) {
+		pr_err("%s : Failed to get image version base address",
+				__func__);
+		return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown");
+	}
+	string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	string_address += SMEM_IMAGE_VERSION_NAME_OFFSET;
+	return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.72s\n",
+			string_address);
+}
+
+static ssize_t
+msm_set_image_version(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	char *store_address;
+
+	if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+		return count;
+	store_address = socinfo_get_image_version_base_address();
+	if (store_address == NULL) {
+		pr_err("%s : Failed to get image version base address",
+				__func__);
+		return count;
+	}
+	store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf);
+	return count;
+}
+
+static ssize_t
+msm_get_image_variant(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	char *string_address;
+
+	string_address = socinfo_get_image_version_base_address();
+	if (string_address == NULL) {
+		pr_err("%s : Failed to get image version base address",
+				__func__);
+		return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE,
+		"Unknown");
+	}
+	string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
+	return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n",
+			string_address);
+}
+
+static ssize_t
+msm_set_image_variant(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	char *store_address;
+
+	if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+		return count;
+	store_address = socinfo_get_image_version_base_address();
+	if (store_address == NULL) {
+		pr_err("%s : Failed to get image version base address",
+				__func__);
+		return count;
+	}
+	store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
+	snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf);
+	return count;
+}
+
+static ssize_t
+msm_get_image_crm_version(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	char *string_address;
+
+	string_address = socinfo_get_image_version_base_address();
+	if (string_address == NULL) {
+		pr_err("%s : Failed to get image version base address",
+				__func__);
+		return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown");
+	}
+	string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
+	return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n",
+			string_address);
+}
+
 static struct sysdev_attribute socinfo_v1_files[] = {
 	_SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
 	_SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
@@ -866,6 +983,54 @@
 			socinfo_show_pmic_die_revision, NULL),
 };
 
+static ssize_t
+msm_set_image_crm_version(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	char *store_address;
+
+	if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+		return count;
+	store_address = socinfo_get_image_version_base_address();
+	if (store_address == NULL) {
+		pr_err("%s : Failed to get image version base address",
+				__func__);
+		return count;
+	}
+	store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
+	snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf);
+	return count;
+}
+
+static ssize_t
+msm_get_image_number(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			current_image);
+}
+
+static ssize_t
+msm_select_image(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	int ret, digit;
+
+	ret = kstrtoint(buf, 10, &digit);
+	if (ret)
+		return ret;
+	if (0 <= digit && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT)
+		current_image = digit;
+	else
+		current_image = 0;
+	return count;
+}
+
+
 static struct device_attribute msm_soc_attr_raw_version =
 	__ATTR(raw_version, S_IRUGO, msm_get_raw_version,  NULL);
 
@@ -902,6 +1067,22 @@
 	__ATTR(pmic_die_revision, S_IRUGO,
 			msm_get_pmic_die_revision, NULL);
 
+static struct device_attribute image_version =
+	__ATTR(image_version, S_IRUGO | S_IWUSR,
+			msm_get_image_version, msm_set_image_version);
+
+static struct device_attribute image_variant =
+	__ATTR(image_variant, S_IRUGO | S_IWUSR,
+			msm_get_image_variant, msm_set_image_variant);
+
+static struct device_attribute image_crm_version =
+	__ATTR(image_crm_version, S_IRUGO | S_IWUSR,
+			msm_get_image_crm_version, msm_set_image_crm_version);
+
+static struct device_attribute select_image =
+	__ATTR(select_image, S_IRUGO | S_IWUGO,
+			msm_get_image_number, msm_select_image);
+
 static struct sysdev_class soc_sysdev_class = {
 	.name = "soc",
 };
@@ -956,6 +1137,10 @@
 	uint32_t legacy_format = socinfo_get_format();
 
 	device_create_file(msm_soc_device, &msm_soc_attr_vendor);
+	device_create_file(msm_soc_device, &image_version);
+	device_create_file(msm_soc_device, &image_variant);
+	device_create_file(msm_soc_device, &image_crm_version);
+	device_create_file(msm_soc_device, &select_image);
 
 	switch (legacy_format) {
 	case 8:
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 58b0513..1149dec 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -788,6 +788,8 @@
 		if (ret < 0)
 			return ret;
 
+		memset(&param, 0, sizeof(param));
+
 		param.fd = ret;
 
 		if (copy_to_user((void __user *) arg, &param,
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index c4f762d..beaf75d 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -105,6 +105,9 @@
 		"RIVA CNTL in_buf_1_size: %d\n"
 		"Modem DCI in_buf_1_size: %d\n"
 		"Modem DCI CMD in_buf_1_size: %d\n"
+		"Received Feature mask from Modem: %d\n"
+		"Received Feature mask from LPASS: %d\n"
+		"Received Feature mask from WCNSS: %d\n"
 		"logging_mode: %d\n"
 		"real_time_mode: %d\n",
 		(unsigned int)driver->smd_data[MODEM_DATA].ch,
@@ -171,6 +174,9 @@
 		(unsigned int)driver->smd_cntl[WCNSS_DATA].buf_in_1_size,
 		(unsigned int)driver->smd_dci[MODEM_DATA].buf_in_1_size,
 		(unsigned int)driver->smd_dci_cmd[MODEM_DATA].buf_in_1_size,
+		driver->rcvd_feature_mask[MODEM_DATA],
+		driver->rcvd_feature_mask[LPASS_DATA],
+		driver->rcvd_feature_mask[WCNSS_DATA],
 		driver->logging_mode,
 		driver->real_time_mode);
 
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index e0a428d..9d9d89b 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -340,6 +340,7 @@
 	struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
 	struct diag_smd_info smd_cmd[NUM_SMD_CMD_CHANNELS];
 	struct diag_smd_info smd_dci_cmd[NUM_SMD_DCI_CMD_CHANNELS];
+	int rcvd_feature_mask[NUM_SMD_CONTROL_CHANNELS];
 	int separate_cmdrsp[NUM_SMD_CONTROL_CHANNELS];
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index 7b24591..3e38a3c 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -207,15 +207,11 @@
 							  ^ ESC_MASK;
 				}
 			} else if (src_byte == CONTROL_CHAR) {
-				dest_ptr[len++] = src_byte;
-				/*
-				 * If this is the first byte in the message,
-				 * then it is part of the command. Otherwise,
-				 * consider it as the last byte of the
-				 * message.
-				 */
 				if (msg_start && i == 0 && src_length > 1)
 					continue;
+				/* Byte 0x7E will be considered
+					as end of packet */
+				dest_ptr[len++] = src_byte;
 				i++;
 				pkt_bnd = 1;
 				break;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index c74ab99..cdd315e 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -203,11 +203,12 @@
 		 * has registered to respond for polling
 		 */
 		return 1;
-	else if (!(driver->smd_data[MODEM_DATA].ch) &&
-					!(chk_apps_master()))
+	else if (!((driver->smd_data[MODEM_DATA].ch) &&
+		 (driver->rcvd_feature_mask[MODEM_DATA])) &&
+		 (chk_apps_master()))
 		/*
 		 * If the apps processor is not the master and the modem
-		 * is not up
+		 * is not up or we did not receive the feature masks from Modem
 		 */
 		return 1;
 	else
@@ -389,7 +390,7 @@
 	 * Do not work with ref_count here in case
 	 * of spurious interrupt
 	 */
-	if (lock->enabled)
+	if (lock->enabled && !wake_lock_active(&lock->read_lock))
 		wake_lock(&lock->read_lock);
 	spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
 }
@@ -1170,6 +1171,18 @@
 	return 0;
 }
 
+int diag_apps_responds()
+{
+	if (chk_apps_only()) {
+		if (driver->smd_data[MODEM_DATA].ch &&
+				driver->rcvd_feature_mask[MODEM_DATA]) {
+			return 0;
+		}
+		return 1;
+	}
+	return 0;
+}
+
 int diag_process_apps_pkt(unsigned char *buf, int len)
 {
 	uint16_t subsys_cmd_code;
@@ -1204,7 +1217,8 @@
 	pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
 	for (i = 0; i < diag_max_reg; i++) {
 		entry = driver->table[i];
-		if (entry.process_id != NO_PROCESS) {
+		if (entry.process_id != NO_PROCESS &&
+				driver->rcvd_feature_mask[entry.client_id]) {
 			if (entry.cmd_code == cmd_code && entry.subsys_id ==
 				 subsys_id && entry.cmd_code_lo <=
 							 subsys_cmd_code &&
@@ -1250,8 +1264,7 @@
 		return diag_process_stm_cmd(buf);
 	}
 	/* Check for Apps Only & get event mask request */
-	else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
-								*buf == 0x81) {
+	else if (diag_apps_responds() && *buf == 0x81) {
 		driver->apps_rsp_buf[0] = 0x81;
 		driver->apps_rsp_buf[1] = 0x0;
 		*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
@@ -1262,8 +1275,8 @@
 		return 0;
 	}
 	/* Get log ID range & Check for Apps Only */
-	else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
-			  && (*buf == 0x73) && *(int *)(buf+4) == 1) {
+	else if (diag_apps_responds() && (*buf == 0x73) &&
+							*(int *)(buf+4) == 1) {
 		driver->apps_rsp_buf[0] = 0x73;
 		*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
 		*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
@@ -1287,8 +1300,8 @@
 		return 0;
 	}
 	/* Respond to Get SSID Range request message */
-	else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
-			 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
+	else if (diag_apps_responds() && (*buf == 0x7d) &&
+							(*(buf+1) == 0x1)) {
 		driver->apps_rsp_buf[0] = 0x7d;
 		driver->apps_rsp_buf[1] = 0x1;
 		driver->apps_rsp_buf[2] = 0x1;
@@ -1345,8 +1358,8 @@
 		return 0;
 	}
 	/* Check for Apps Only Respond to Get Subsys Build mask */
-	else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
-			 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
+	else if (diag_apps_responds() && (*buf == 0x7d) &&
+							(*(buf+1) == 0x2)) {
 		ssid_first = *(uint16_t *)(buf + 2);
 		ssid_last = *(uint16_t *)(buf + 4);
 		ssid_range = 4 * (ssid_last - ssid_first + 1);
@@ -2444,6 +2457,7 @@
 	for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 		driver->separate_cmdrsp[i] = 0;
 		driver->peripheral_supports_stm[i] = DISABLE_STM;
+		driver->rcvd_feature_mask[i] = 0;
 	}
 
 	for (i = 0; i < NUM_STM_PROCESSORS; i++) {
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index c6e1273..1a4601a 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -53,6 +53,7 @@
 void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
 int diag_process_apps_pkt(unsigned char *buf, int len);
 void diag_reset_smd_data(int queue);
+int diag_apps_responds(void);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index e0deef3..d3c311d 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -37,6 +37,9 @@
 	diag_clear_reg(smd_info->peripheral);
 	reg_dirty ^= smd_info->peripheral_mask;
 
+	/* Reset the feature mask flag */
+	driver->rcvd_feature_mask[smd_info->peripheral] = 0;
+
 	smd_info->notify_context = 0;
 }
 
@@ -158,14 +161,21 @@
 			msg = buf+HDR_SIZ;
 			range = buf+HDR_SIZ+
 					sizeof(struct diag_ctrl_msg);
+			if (msg->count_entries == 0) {
+				pr_debug("diag: In %s, received reg tbl with no entries\n",
+								__func__);
+				buf = buf + HDR_SIZ + data_len;
+				continue;
+			}
 			pkt_params->count = msg->count_entries;
 			pkt_params->params = kzalloc(pkt_params->count *
 				sizeof(struct bindpkt_params), GFP_KERNEL);
-			if (ZERO_OR_NULL_PTR(pkt_params->params)) {
-				pr_alert("diag: In %s, Memory alloc fail\n",
-					__func__);
-				kfree(pkt_params);
-				return flag;
+			if (!pkt_params->params) {
+				pr_alert("diag: In %s, Memory alloc fail for cmd_code: %d, subsys: %d\n",
+						__func__, msg->cmd_code,
+						msg->subsysid);
+				buf = buf + HDR_SIZ + data_len;
+				continue;
 			}
 			temp = pkt_params->params;
 			for (j = 0; j < pkt_params->count; j++) {
@@ -195,6 +205,8 @@
 			int feature_mask_len = *(int *)(buf+8);
 			if (feature_mask_len > 0) {
 				int periph = smd_info->peripheral;
+				driver->rcvd_feature_mask[smd_info->peripheral]
+									= 1;
 				feature_mask = *(uint8_t *)(buf+12);
 				if (periph == MODEM_DATA)
 					driver->log_on_demand_support =
@@ -262,31 +274,39 @@
 {
 	int temp_real_time = MODE_REALTIME, i;
 
-	/* If any of the process is voting for Real time, then Diag
-	   should be in real time mode irrespective of other clauses. If
-	   USB is connected, check what the memory device process is
-	   voting for. If it is voting for Non real time, the final mode
-	   should be Non real time, real time otherwise. If USB is
-	   disconncted and no process is voting for real time, the
-	   resultant mode should be Non Real Time.
-	*/
-	if ((driver->proc_rt_vote_mask & driver->proc_active_mask) &&
-					(driver->proc_active_mask != 0))
-			temp_real_time = MODE_REALTIME;
-	else if (driver->usb_connected)
+	if (driver->proc_active_mask == 0) {
+		/* There are no DCI or Memory Device processes. Diag should
+		 * be in Real Time mode irrespective of USB connection
+		 */
+		temp_real_time = MODE_REALTIME;
+	} else if (driver->proc_rt_vote_mask & driver->proc_active_mask) {
+		/* Atleast one process is alive and is voting for Real Time
+		 * data - Diag should be in real time mode irrespective of USB
+		 * connection.
+		 */
+		temp_real_time = MODE_REALTIME;
+	} else if (driver->usb_connected) {
+		/* If USB is connected, check individual process. If Memory
+		 * Device Mode is active, set the mode requested by Memory
+		 * Device process. Set to realtime mode otherwise.
+		 */
 		if ((driver->proc_rt_vote_mask & DIAG_PROC_MEMORY_DEVICE) == 0)
 			temp_real_time = MODE_NONREALTIME;
 		else
 			temp_real_time = MODE_REALTIME;
-	else
+	} else {
+		/* We come here if USB is not connected and the active
+		 * processes are voting for Non realtime mode.
+		 */
 		temp_real_time = MODE_NONREALTIME;
+	}
 
 	if (temp_real_time != driver->real_time_mode) {
 		for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
 			diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i],
 							temp_real_time);
 	} else {
-		pr_info("diag: did not update real time mode, already in the req mode %d",
+		pr_debug("diag: did not update real time mode, already in the req mode %d",
 					temp_real_time);
 	}
 	if (driver->real_time_update_busy > 0)
@@ -297,9 +317,15 @@
 {
 	int temp_real_time = MODE_REALTIME, i;
 
-	if (!(driver->proc_rt_vote_mask & driver->proc_active_mask) &&
-					(driver->proc_active_mask != 0))
+	if (driver->proc_active_mask == 0) {
+		/* There are no DCI or Memory Device processes. Diag should
+		 * be in Real Time mode.
+		 */
+		temp_real_time = MODE_REALTIME;
+	} else if (!(driver->proc_rt_vote_mask & driver->proc_active_mask)) {
+		/* No active process is voting for real time mode */
 		temp_real_time = MODE_NONREALTIME;
+	}
 
 	if (temp_real_time != driver->real_time_mode) {
 		for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
@@ -321,12 +347,17 @@
 	char buf[sizeof(struct diag_ctrl_msg_diagmode)];
 	int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
 	int wr_size = -ENOMEM, retry_count = 0, timer;
+	struct diag_smd_info *data = NULL;
 
 	/* For now only allow the modem to receive the message */
 	if (!smd_info || smd_info->type != SMD_CNTL_TYPE ||
 		(smd_info->peripheral != MODEM_DATA))
 		return;
 
+	data = &driver->smd_data[smd_info->peripheral];
+	if (!data)
+		return;
+
 	mutex_lock(&driver->diag_cntl_mutex);
 	diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
 	diagmode.ctrl_pkt_data_len = 36;
@@ -362,11 +393,9 @@
 				for (timer = 0; timer < 5; timer++)
 					udelay(2000);
 			} else {
-				struct diag_smd_info *data =
+				data =
 				&driver->smd_data[smd_info->peripheral];
 				driver->real_time_mode = real_time;
-				process_lock_enabling(&data->nrt_lock,
-								real_time);
 				break;
 			}
 		}
@@ -378,6 +407,7 @@
 		pr_err("diag: ch invalid, feature update on proc %d\n",
 				smd_info->peripheral);
 	}
+	process_lock_enabling(&data->nrt_lock, real_time);
 
 	mutex_unlock(&driver->diag_cntl_mutex);
 }
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 5e2acfb..fc6df7b 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -151,6 +151,38 @@
 
 	  If unsure, say 'N' here to avoid potential power penalty.
 
+config CORESIGHT_AUDIO_ETM
+	bool "Audio processor ETM trace support"
+	help
+	  Enables support for ETM trace collection on audio processor using
+	  CoreSight framework. Enabling this will allow turning on ETM tracing
+	  on audio processor via sysfs by configuring the required CoreSight
+	  components.
+
+config CORESIGHT_MODEM_ETM
+	bool "Modem processor ETM trace support"
+	help
+	  Enables support for ETM trace collection on modem processor using
+	  CoreSight framework. Enabling this will allow turning on ETM tracing
+	  on modem processor via sysfs by configuring the required CoreSight
+	  components.
+
+config CORESIGHT_WCN_ETM
+	bool "Wireless subsystem processor ETM trace support"
+	help
+	  Enables support for ETM trace collection on wireless subsystem
+	  processor  using CoreSight framework. Enabling this will allow
+	  turning on ETM tracing on wireless subsystem via sysfs by configuring
+	  the required CoreSight components.
+
+config CORESIGHT_RPM_ETM
+	bool "RPM processor ETM trace support"
+	help
+	  Enables support for ETM trace collection on RPM processor using
+	  CoreSight framework. Enabling this will allow turning on ETM
+	  tracing on RPM processor via sysfs by configuring the required
+	  CoreSight components.
+
 endif
 
 config CORESIGHT_EVENT
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 23352a7..9d93a6c 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -13,4 +13,8 @@
 obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
 obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
 obj-$(CONFIG_CORESIGHT_ETM) += coresight-etm.o coresight-etm-cp14.o
+obj-$(CONFIG_CORESIGHT_AUDIO_ETM) += coresight-audio-etm.o
+obj-$(CONFIG_CORESIGHT_MODEM_ETM) += coresight-modem-etm.o
+obj-$(CONFIG_CORESIGHT_WCN_ETM) += coresight-wcn-etm.o
+obj-$(CONFIG_CORESIGHT_RPM_ETM) += coresight-rpm-etm.o
 obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
diff --git a/drivers/coresight/coresight-audio-etm.c b/drivers/coresight/coresight-audio-etm.c
new file mode 100644
index 0000000..cdf44bf
--- /dev/null
+++ b/drivers/coresight/coresight-audio-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct audio_etm_drvdata {
+	struct device			*dev;
+	struct coresight_device		*csdev;
+};
+
+static int audio_etm_enable(struct coresight_device *csdev)
+{
+	struct audio_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Audio ETM tracing enabled\n");
+	return 0;
+}
+
+
+static void audio_etm_disable(struct coresight_device *csdev)
+{
+	struct audio_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Audio ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source audio_etm_source_ops = {
+	.enable		= audio_etm_enable,
+	.disable	= audio_etm_disable,
+};
+
+static const struct coresight_ops audio_cs_ops = {
+	.source_ops	= &audio_etm_source_ops,
+};
+
+static int audio_etm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct audio_etm_drvdata *drvdata;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &audio_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "Audio ETM initialized\n");
+	return 0;
+}
+
+static int audio_etm_remove(struct platform_device *pdev)
+{
+	struct audio_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id audio_etm_match[] = {
+	{.compatible = "qcom,coresight-audio-etm"},
+	{}
+};
+
+static struct platform_driver audio_etm_driver = {
+	.probe          = audio_etm_probe,
+	.remove         = audio_etm_remove,
+	.driver         = {
+		.name   = "coresight-audio-etm",
+		.owner	= THIS_MODULE,
+		.of_match_table = audio_etm_match,
+	},
+};
+
+int __init audio_etm_init(void)
+{
+	return platform_driver_register(&audio_etm_driver);
+}
+module_init(audio_etm_init);
+
+void __exit audio_etm_exit(void)
+{
+	platform_driver_unregister(&audio_etm_driver);
+}
+module_exit(audio_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Audio ETM driver");
diff --git a/drivers/coresight/coresight-modem-etm.c b/drivers/coresight/coresight-modem-etm.c
new file mode 100644
index 0000000..4c8075c
--- /dev/null
+++ b/drivers/coresight/coresight-modem-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct modem_etm_drvdata {
+	struct device			*dev;
+	struct coresight_device		*csdev;
+};
+
+static int modem_etm_enable(struct coresight_device *csdev)
+{
+	struct modem_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Modem ETM tracing enabled\n");
+	return 0;
+}
+
+
+static void modem_etm_disable(struct coresight_device *csdev)
+{
+	struct modem_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Modem ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source modem_etm_source_ops = {
+	.enable		= modem_etm_enable,
+	.disable	= modem_etm_disable,
+};
+
+static const struct coresight_ops modem_cs_ops = {
+	.source_ops	= &modem_etm_source_ops,
+};
+
+static int modem_etm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct modem_etm_drvdata *drvdata;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &modem_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return  PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "Modem ETM initialized\n");
+	return 0;
+}
+
+static int modem_etm_remove(struct platform_device *pdev)
+{
+	struct modem_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id modem_etm_match[] = {
+	{.compatible = "qcom,coresight-modem-etm"},
+	{}
+};
+
+static struct platform_driver modem_etm_driver = {
+	.probe          = modem_etm_probe,
+	.remove         = modem_etm_remove,
+	.driver         = {
+		.name   = "coresight-modem-etm",
+		.owner	= THIS_MODULE,
+		.of_match_table = modem_etm_match,
+	},
+};
+
+int __init modem_etm_init(void)
+{
+	return platform_driver_register(&modem_etm_driver);
+}
+module_init(modem_etm_init);
+
+void __exit modem_etm_exit(void)
+{
+	platform_driver_unregister(&modem_etm_driver);
+}
+module_exit(modem_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Modem ETM driver");
diff --git a/drivers/coresight/coresight-rpm-etm.c b/drivers/coresight/coresight-rpm-etm.c
new file mode 100644
index 0000000..e752e4f
--- /dev/null
+++ b/drivers/coresight/coresight-rpm-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct rpm_etm_drvdata {
+	struct device			*dev;
+	struct coresight_device		*csdev;
+};
+
+static int rpm_etm_enable(struct coresight_device *csdev)
+{
+	struct rpm_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "RPM ETM tracing enabled\n");
+	return 0;
+}
+
+
+static void rpm_etm_disable(struct coresight_device *csdev)
+{
+	struct rpm_etm_drvdata *drvdata =
+		 dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "RPM ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source rpm_etm_source_ops = {
+	.enable		= rpm_etm_enable,
+	.disable	= rpm_etm_disable,
+};
+
+static const struct coresight_ops rpm_cs_ops = {
+	.source_ops	= &rpm_etm_source_ops,
+};
+
+static int rpm_etm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct rpm_etm_drvdata *drvdata;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &rpm_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return  PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "RPM ETM initialized\n");
+	return 0;
+}
+
+static int rpm_etm_remove(struct platform_device *pdev)
+{
+	struct rpm_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id rpm_etm_match[] = {
+	{.compatible = "qcom,coresight-rpm-etm"},
+	{}
+};
+
+static struct platform_driver rpm_etm_driver = {
+	.probe          = rpm_etm_probe,
+	.remove         = rpm_etm_remove,
+	.driver         = {
+		.name   = "coresight-rpm-etm",
+		.owner	= THIS_MODULE,
+		.of_match_table = rpm_etm_match,
+	},
+};
+
+int __init rpm_etm_init(void)
+{
+	return platform_driver_register(&rpm_etm_driver);
+}
+module_init(rpm_etm_init);
+
+void __exit rpm_etm_exit(void)
+{
+	platform_driver_unregister(&rpm_etm_driver);
+}
+module_exit(rpm_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight RPM ETM driver");
diff --git a/drivers/coresight/coresight-wcn-etm.c b/drivers/coresight/coresight-wcn-etm.c
new file mode 100644
index 0000000..44852fb
--- /dev/null
+++ b/drivers/coresight/coresight-wcn-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct wcn_etm_drvdata {
+	struct device			*dev;
+	struct coresight_device		*csdev;
+};
+
+static int wcn_etm_enable(struct coresight_device *csdev)
+{
+	struct wcn_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Wireless ETM tracing enabled\n");
+	return 0;
+}
+
+
+static void wcn_etm_disable(struct coresight_device *csdev)
+{
+	struct wcn_etm_drvdata *drvdata =
+		dev_get_drvdata(csdev->dev.parent);
+
+	dev_info(drvdata->dev, "Wireless ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source wcn_etm_source_ops = {
+	.enable		= wcn_etm_enable,
+	.disable	= wcn_etm_disable,
+};
+
+static const struct coresight_ops wcn_cs_ops = {
+	.source_ops	= &wcn_etm_source_ops,
+};
+
+static int wcn_etm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct wcn_etm_drvdata *drvdata;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &wcn_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return  PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "Wireless ETM initialized\n");
+	return 0;
+}
+
+static int wcn_etm_remove(struct platform_device *pdev)
+{
+	struct wcn_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id wcn_etm_match[] = {
+	{.compatible = "qcom,coresight-wcn-etm"},
+	{}
+};
+
+static struct platform_driver wcn_etm_driver = {
+	.probe          = wcn_etm_probe,
+	.remove         = wcn_etm_remove,
+	.driver         = {
+		.name   = "coresight-wcn-etm",
+		.owner	= THIS_MODULE,
+		.of_match_table = wcn_etm_match,
+	},
+};
+
+int __init wcn_etm_init(void)
+{
+	return platform_driver_register(&wcn_etm_driver);
+}
+module_init(wcn_etm_init);
+
+void __exit wcn_etm_exit(void)
+{
+	platform_driver_unregister(&wcn_etm_driver);
+}
+module_exit(wcn_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Wireless ETM driver");
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 374170d..975a42f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1114,10 +1114,10 @@
 #ifdef CONFIG_HOTPLUG_CPU
 	strncpy(per_cpu(cpufreq_policy_save, cpu).gov, data->governor->name,
 			CPUFREQ_NAME_LEN);
-	per_cpu(cpufreq_policy_save, cpu).min = data->min;
-	per_cpu(cpufreq_policy_save, cpu).max = data->max;
-	pr_debug("Saving CPU%d policy min %d and max %d\n",
-			cpu, data->min, data->max);
+	per_cpu(cpufreq_policy_save, cpu).min = data->user_policy.min;
+	per_cpu(cpufreq_policy_save, cpu).max = data->user_policy.max;
+	pr_debug("Saving CPU%d user policy min %d and max %d\n",
+			cpu, data->user_policy.min, data->user_policy.max);
 #endif
 
 	/* if we have other CPUs still registered, we need to unlink them,
@@ -1143,9 +1143,11 @@
 #ifdef CONFIG_HOTPLUG_CPU
 			strncpy(per_cpu(cpufreq_policy_save, j).gov,
 				data->governor->name, CPUFREQ_NAME_LEN);
-			per_cpu(cpufreq_policy_save, j).min = data->min;
-			per_cpu(cpufreq_policy_save, j).max = data->max;
-			pr_debug("Saving CPU%d policy min %d and max %d\n",
+			per_cpu(cpufreq_policy_save, j).min
+						= data->user_policy.min;
+			per_cpu(cpufreq_policy_save, j).max
+						= data->user_policy.max;
+			pr_debug("Saving CPU%d user policy min %d and max %d\n",
 					j, data->min, data->max);
 #endif
 			cpu_dev = get_cpu_device(j);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e6b2a3c..af494c6 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -144,6 +144,7 @@
 	unsigned int sampling_down_factor;
 	int          powersave_bias;
 	unsigned int io_is_busy;
+	unsigned int input_boost;
 } dbs_tuners_ins = {
 	.up_threshold_multi_core = DEF_FREQUENCY_UP_THRESHOLD,
 	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
@@ -155,6 +156,7 @@
 	.powersave_bias = 0,
 	.sync_freq = 0,
 	.optimal_freq = 0,
+	.input_boost = 0,
 };
 
 static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
@@ -319,6 +321,7 @@
 show_one(optimal_freq, optimal_freq);
 show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
 show_one(sync_freq, sync_freq);
+show_one(input_boost, input_boost);
 
 static ssize_t show_powersave_bias
 (struct kobject *kobj, struct attribute *attr, char *buf)
@@ -396,6 +399,18 @@
 	return count;
 }
 
+static ssize_t store_input_boost(struct kobject *a, struct attribute *b,
+				const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+	dbs_tuners_ins.input_boost = input;
+	return count;
+}
+
 static ssize_t store_sync_freq(struct kobject *a, struct attribute *b,
 				   const char *buf, size_t count)
 {
@@ -680,6 +695,7 @@
 define_one_global_rw(optimal_freq);
 define_one_global_rw(up_threshold_any_cpu_load);
 define_one_global_rw(sync_freq);
+define_one_global_rw(input_boost);
 
 static struct attribute *dbs_attributes[] = {
 	&sampling_rate_min.attr,
@@ -694,6 +710,7 @@
 	&optimal_freq.attr,
 	&up_threshold_any_cpu_load.attr,
 	&sync_freq.attr,
+	&input_boost.attr,
 	NULL
 };
 
@@ -1006,6 +1023,7 @@
 	struct cpu_dbs_info_s *this_dbs_info;
 	struct dbs_work_struct *dbs_work;
 	unsigned int cpu;
+	unsigned int target_freq;
 
 	dbs_work = container_of(work, struct dbs_work_struct, work);
 	cpu = dbs_work->cpu;
@@ -1022,14 +1040,19 @@
 		goto bail_incorrect_governor;
 	}
 
-	if (policy->cur < policy->max) {
+	if (dbs_tuners_ins.input_boost)
+		target_freq = dbs_tuners_ins.input_boost;
+	else
+		target_freq = policy->max;
+
+	if (policy->cur < target_freq) {
 		/*
 		 * Arch specific cpufreq driver may fail.
 		 * Don't update governor frequency upon failure.
 		 */
-		if (__cpufreq_driver_target(policy, policy->max,
+		if (__cpufreq_driver_target(policy, target_freq,
 					CPUFREQ_RELATION_L) >= 0)
-			policy->cur = policy->max;
+			policy->cur = target_freq;
 
 		this_dbs_info->prev_cpu_idle = get_cpu_idle_time(cpu,
 				&this_dbs_info->prev_cpu_wall);
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index 3e1a7ee..c2b65ba 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -285,7 +285,7 @@
 static struct ion_iommu_map *__ion_iommu_map(struct ion_iommu_meta *meta,
 		int domain_num, int partition_num, unsigned long align,
 		unsigned long iova_length, unsigned long flags,
-		unsigned long *iova)
+		ion_phys_addr_t *iova)
 {
 	struct ion_iommu_map *data;
 	int ret;
@@ -367,7 +367,7 @@
 
 int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
 			int domain_num, int partition_num, unsigned long align,
-			unsigned long iova_length, unsigned long *iova,
+			unsigned long iova_length, ion_phys_addr_t *iova,
 			unsigned long *buffer_size,
 			unsigned long flags, unsigned long iommu_flags)
 {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 8c8cb01..50a0d12 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -120,6 +120,7 @@
 	.ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY,
 	.fast_hang_detect = 1,
 	.long_ib_detect = 1,
+	.intr_mask = 0xFFFFFFFF,
 };
 
 /* This set of registers are used for Hang detection
@@ -287,7 +288,7 @@
  */
 
 int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
-	struct kgsl_perfcounter_read_group *reads, unsigned int count)
+	struct kgsl_perfcounter_read_group __user *reads, unsigned int count)
 {
 	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
 	struct adreno_perfcount_group *group;
@@ -307,12 +308,6 @@
 	if (reads == NULL || count == 0 || count > 100)
 		return -EINVAL;
 
-	/* verify valid inputs group ids and countables */
-	for (i = 0; i < count; i++) {
-		if (reads[i].groupid >= counters->group_count)
-			return -EINVAL;
-	}
-
 	list = kmalloc(sizeof(struct kgsl_perfcounter_read_group) * count,
 			GFP_KERNEL);
 	if (!list)
@@ -326,8 +321,15 @@
 
 	/* list iterator */
 	for (j = 0; j < count; j++) {
+
 		list[j].value = 0;
 
+		/* Verify that the group ID is within range */
+		if (list[j].groupid >= counters->group_count) {
+			ret = -EINVAL;
+			goto done;
+		}
+
 		group = &(counters->groups[list[j].groupid]);
 
 		/* group/counter iterator */
@@ -335,8 +337,7 @@
 			if (group->regs[i].countable == list[j].countable) {
 				list[j].value =
 					adreno_dev->gpudev->perfcounter_read(
-					adreno_dev, list[j].groupid,
-					i, group->regs[i].offset);
+					adreno_dev, list[j].groupid, i);
 				break;
 			}
 		}
@@ -599,6 +600,33 @@
 	return -EINVAL;
 }
 
+/**
+ * adreno_perfcounter_restore() - Restore performance counters
+ * @adreno_dev: adreno device to configure
+ *
+ * Load the physical performance counters with 64 bit value which are
+ * saved on GPU power collapse.
+ */
+static inline void adreno_perfcounter_restore(struct adreno_device *adreno_dev)
+{
+	if (adreno_dev->gpudev->perfcounter_restore)
+		adreno_dev->gpudev->perfcounter_restore(adreno_dev);
+}
+
+/**
+ * adreno_perfcounter_save() - Save performance counters
+ * @adreno_dev: adreno device to configure
+ *
+ * Save the performance counter values before GPU power collapse.
+ * The saved values are restored on restart.
+ * This ensures physical counters are coherent across power-collapse.
+ */
+static inline void adreno_perfcounter_save(struct adreno_device *adreno_dev)
+{
+	if (adreno_dev->gpudev->perfcounter_save)
+		adreno_dev->gpudev->perfcounter_save(adreno_dev);
+}
+
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 {
 	irqreturn_t result;
@@ -951,8 +979,11 @@
 	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
 
 	context = kgsl_context_get(device, context_id);
-	if (context == NULL)
+
+	if (context == NULL) {
+		kgsl_mmu_device_setstate(&device->mmu, KGSL_CONTEXT_INVALID);
 		return;
+	}
 
 	adreno_ctx = ADRENO_CONTEXT(context);
 
@@ -1704,11 +1735,14 @@
 
 	adreno_perfcounter_init(device);
 
+	if (adreno_dev->gpudev->irq_init)
+		adreno_dev->gpudev->irq_init(adreno_dev);
+
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
 
-	/* Certain targets need the fixup.  You know who you are */
-	if (adreno_is_a330v2(adreno_dev))
+	/* Enable the power on shader corruption fix for all A3XX targets */
+	if (adreno_is_a3xx(adreno_dev))
 		adreno_a3xx_pwron_fixup_init(adreno_dev);
 
 	return 0;
@@ -1768,11 +1802,15 @@
 		adreno_dev->gpudev->soft_reset(adreno_dev);
 	}
 
+	/* Restore performance counter registers with saved values */
+	adreno_perfcounter_restore(adreno_dev);
+
 	/* Start the GPU */
 	adreno_dev->gpudev->start(adreno_dev);
 
+	kgsl_atomic_set(&adreno_dev->hang_intr_set, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-	device->ftbl->irqctrl(device, 1);
+	device->ftbl->irqctrl(device, adreno_dev->intr_mask);
 
 	status = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
 	if (status)
@@ -1823,6 +1861,9 @@
 
 	adreno_ocmem_gmem_free(adreno_dev);
 
+	/* Save physical performance counter values before GPU power down*/
+	adreno_perfcounter_save(adreno_dev);
+
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
 
@@ -2206,8 +2247,7 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int ret;
 
-	/* If the jump table index is 0 soft reset is not supported */
-	if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+	if (!adreno_dev->gpudev->soft_reset) {
 		dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
 		return -EINVAL;
 	}
@@ -2226,21 +2266,32 @@
 	/* Make sure we are totally awake */
 	kgsl_pwrctrl_enable(device);
 
+	/* save physical performance counter values before GPU soft reset */
+	adreno_perfcounter_save(adreno_dev);
+
 	/* Reset the GPU */
 	adreno_dev->gpudev->soft_reset(adreno_dev);
 
+	/* Restore physical performance counter values after soft reset */
+	adreno_perfcounter_restore(adreno_dev);
+
 	/* Reinitialize the GPU */
 	adreno_dev->gpudev->start(adreno_dev);
 
 	/* Enable IRQ */
+	kgsl_atomic_set(&adreno_dev->hang_intr_set, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-	device->ftbl->irqctrl(device, 1);
+	device->ftbl->irqctrl(device, adreno_dev->intr_mask);
 
 	/*
-	 * Restart the ringbuffer - we can go down the warm start path because
-	 * power was never yanked
+	 * If we have offsets for the jump tables we can try to do a warm start,
+	 * otherwise do a full ringbuffer restart
 	 */
-	ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+	if (adreno_dev->pm4_jt_idx)
+		ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+	else
+		ret = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
+
 	if (ret)
 		return ret;
 
@@ -2973,6 +3024,52 @@
 				(adreno_dev->long_ib_detect ? 1 : 0));
 }
 
+/**
+ * _ft_hang_intr_status_store() -  Routine to configure GPU
+ * hang interrupt
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ */
+static int _ft_hang_intr_status_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+	int ret = 0;
+
+	if (adreno_dev == NULL)
+		return 0;
+
+	mutex_lock(&adreno_dev->dev.mutex);
+	if (adreno_hang_intr_supported(adreno_dev))
+		ret = _ft_sysfs_store(buf, count, &adreno_dev->hang_intr_en);
+	mutex_unlock(&adreno_dev->dev.mutex);
+
+	return ret;
+
+}
+
+/**
+ * _ft_hang_intr_status_show() -  Routine to show GPU hang
+ * interrupt enable status
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static int _ft_hang_intr_status_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+	if (adreno_dev == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", (adreno_dev->hang_intr_en &&
+			(adreno_hang_intr_supported(adreno_dev))) ? 1 : 0);
+
+}
 
 #define FT_DEVICE_ATTR(name) \
 	DEVICE_ATTR(name, 0644,	_ ## name ## _show, _ ## name ## _store);
@@ -2981,6 +3078,7 @@
 FT_DEVICE_ATTR(ft_pagefault_policy);
 FT_DEVICE_ATTR(ft_fast_hang_detect);
 FT_DEVICE_ATTR(ft_long_ib_detect);
+FT_DEVICE_ATTR(ft_hang_intr_status);
 
 
 const struct device_attribute *ft_attr_list[] = {
@@ -2988,6 +3086,7 @@
 	&dev_attr_ft_pagefault_policy,
 	&dev_attr_ft_fast_hang_detect,
 	&dev_attr_ft_long_ib_detect,
+	&dev_attr_ft_hang_intr_status,
 	NULL,
 };
 
@@ -3151,6 +3250,10 @@
 	unsigned int rptr;
 
 	do {
+
+		if (kgsl_atomic_read(&adreno_dev->hang_intr_set))
+			return -ETIMEDOUT;
+
 		/*
 		 * Wait is "jiffies" first time in the loop to start
 		 * GPU stall detection immediately.
@@ -3201,6 +3304,9 @@
 			return 0;
 
 		/* Dont wait for timeout, detect hang faster.  */
+		if (kgsl_atomic_read(&adreno_dev->hang_intr_set))
+			goto err;
+
 		if (time_after(jiffies, wait_time_part)) {
 			wait_time_part = jiffies +
 				msecs_to_jiffies(KGSL_TIMEOUT_PART);
@@ -3674,20 +3780,14 @@
 			}
 		}
 		for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+			if (ft_detect_regs[i] == 0)
+				continue;
 			if (curr_reg_val[i] != prev_reg_val[i])
 				fast_hang_detected = 0;
 		}
 
-		if (fast_hang_detected) {
-			KGSL_FT_ERR(device,
-				"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
-				" on global ts %d\n",
-				pid_name, context ? context->id : 0,
-				(kgsl_readtimestamp(device, context,
-				KGSL_TIMESTAMP_RETIRED) + 1),
-				curr_global_ts + 1);
+		if (fast_hang_detected)
 			return 1;
-		}
 
 		if (curr_context != NULL) {
 
@@ -3735,8 +3835,12 @@
 
 	/* If hangs are not detected copy the current reg values
 	 * to previous values and return no hang */
-	for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
-			prev_reg_val[i] = curr_reg_val[i];
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+		if (ft_detect_regs[i] == 0)
+			continue;
+		prev_reg_val[i] = curr_reg_val[i];
+	}
+
 	return 0;
 }
 
@@ -4059,10 +4163,10 @@
 	}
 }
 
-void adreno_irqctrl(struct kgsl_device *device, int state)
+void adreno_irqctrl(struct kgsl_device *device, unsigned int mask)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	adreno_dev->gpudev->irq_control(adreno_dev, state);
+	adreno_dev->gpudev->irq_control(adreno_dev, mask);
 }
 
 static unsigned int adreno_gpuid(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index a837574..8f48440 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -127,6 +127,9 @@
 	unsigned int pix_shader_start;
 	unsigned int instruction_size;
 	unsigned int ib_check_level;
+	atomic_t hang_intr_set;
+	unsigned int hang_intr_en;
+	unsigned int intr_mask;
 	unsigned int fast_hang_detect;
 	unsigned int ft_policy;
 	unsigned int long_ib_detect;
@@ -164,12 +167,18 @@
  * @kernelcount: number of user space users of the register
  * @usercount: number of kernel users of the register
  * @offset: register hardware offset
+ * @load_bit: The bit number in LOAD register which corresponds to this counter
+ * @select: The countable register offset
+ * @value: The 64 bit countable register value
  */
 struct adreno_perfcount_register {
 	unsigned int countable;
 	unsigned int kernelcount;
 	unsigned int usercount;
 	unsigned int offset;
+	int load_bit;
+	unsigned int select;
+	uint64_t value;
 };
 
 /**
@@ -194,6 +203,9 @@
 	unsigned int group_count;
 };
 
+#define ADRENO_PERFCOUNTER_GROUP(core, name) { core##_perfcounters_##name, \
+	ARRAY_SIZE(core##_perfcounters_##name), __stringify(name) }
+
 /**
  * adreno_regs: List of registers that are used in kgsl driver for all
  * 3D devices. Each device type has different offset value for the same
@@ -286,18 +298,22 @@
 	void (*ctxt_draw_workaround)(struct adreno_device *,
 					struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
-	void (*irq_control)(struct adreno_device *, int);
+	void (*irq_control)(struct adreno_device *, unsigned int);
 	unsigned int (*irq_pending)(struct adreno_device *);
+	void (*irq_init)(struct adreno_device *);
 	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 	int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
 	void (*perfcounter_init)(struct adreno_device *);
+	void (*perfcounter_save)(struct adreno_device *);
+	void (*perfcounter_restore)(struct adreno_device *);
 	void (*start)(struct adreno_device *);
 	unsigned int (*busy_cycles)(struct adreno_device *);
 	void (*perfcounter_enable)(struct adreno_device *, unsigned int group,
 		unsigned int counter, unsigned int countable);
 	uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
-		unsigned int group, unsigned int counter,
-		unsigned int offset);
+		unsigned int group, unsigned int counter);
+	void (*perfcounter_write)(struct adreno_device *adreno_dev,
+		unsigned int group, unsigned int counter);
 	int (*coresight_enable) (struct kgsl_device *device);
 	void (*coresight_disable) (struct kgsl_device *device);
 	void (*coresight_config_debug_reg) (struct kgsl_device *device,
@@ -367,8 +383,7 @@
 #define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE     BIT(1)
 #define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE   BIT(2)
 #define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT    BIT(3)
-#define KGSL_FT_PAGEFAULT_DEFAULT_POLICY     (KGSL_FT_PAGEFAULT_INT_ENABLE + \
-					KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+#define KGSL_FT_PAGEFAULT_DEFAULT_POLICY     KGSL_FT_PAGEFAULT_INT_ENABLE
 
 extern struct adreno_gpudev adreno_a2xx_gpudev;
 extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -755,4 +770,29 @@
 static inline void adreno_debugfs_init(struct kgsl_device *device) { }
 #endif
 
+/* 
+ * adreno_hang_intr_supported() - Returns if hang interrupt is supported
+ * @adreno_dev:		Pointer to the the adreno device
+ */
+static inline bool adreno_hang_intr_supported(struct adreno_device *adreno_dev)
+{
+	bool ret = 0;
+	if (adreno_is_a330v2(adreno_dev))
+		ret = 1;
+	return ret;
+}
+
+/*
+ * adreno_fatal_err_work() - Schedules a work to do GFT on fatal error
+ * @adreno_dev:		Pointer to the the adreno device
+ */
+static inline void adreno_fatal_err_work(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+
+	/* If hang_intr_set is 0, set it to 1 and queue work */
+	if (!atomic_cmpxchg(&adreno_dev->hang_intr_set, 0, 1))
+		/* Schedule work to do fault tolerance */
+		queue_work(device->work_queue, &device->hang_intr_ws);
+}
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 3d72c5c..63e3871 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1833,11 +1833,12 @@
 	return result;
 }
 
-static void a2xx_irq_control(struct adreno_device *adreno_dev, int state)
+static void a2xx_irq_control(struct adreno_device *adreno_dev,
+							 unsigned int mask)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (state) {
+	if (mask) {
 		kgsl_regwrite(device, REG_RBBM_INT_CNTL, RBBM_INT_MASK);
 		kgsl_regwrite(device, REG_CP_INT_CNTL, CP_INT_MASK);
 		kgsl_regwrite(device, MH_INTERRUPT_MASK,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f9110ea..5778e9e 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -13,6 +13,7 @@
 
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/ratelimit.h>
 #include <mach/socinfo.h>
 
 #include "kgsl.h"
@@ -3022,6 +3023,8 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	const char *err = "";
+	/* Limit to 10 messages every 5 seconds */
+	static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
 
 	switch (bit) {
 	case A3XX_INT_RBBM_AHB_ERROR: {
@@ -3033,8 +3036,8 @@
 		 * Return the word address of the erroring register so that it
 		 * matches the register specification
 		 */
-
-		KGSL_DRV_CRIT(device,
+		if (!__ratelimit(&ratelimit_state))
+			KGSL_DRV_CRIT(device,
 			"RBBM | AHB bus error | %s | addr=%x | ports=%x:%x\n",
 			reg & (1 << 28) ? "WRITE" : "READ",
 			(reg & 0xFFFFF) >> 2, (reg >> 20) & 0x3,
@@ -3059,34 +3062,17 @@
 	case A3XX_INT_VFD_ERROR:
 		err = "VFD: Out of bounds access";
 		break;
-	case A3XX_INT_CP_T0_PACKET_IN_IB:
-		err = "ringbuffer TO packet in IB interrupt";
-		break;
-	case A3XX_INT_CP_OPCODE_ERROR:
-		err = "ringbuffer opcode error interrupt";
-		break;
-	case A3XX_INT_CP_RESERVED_BIT_ERROR:
-		err = "ringbuffer reserved bit error interrupt";
-		break;
-	case A3XX_INT_CP_HW_FAULT:
-		err = "ringbuffer hardware fault";
-		break;
-	case A3XX_INT_CP_REG_PROTECT_FAULT:
-		err = "ringbuffer protected mode error interrupt";
-		break;
-	case A3XX_INT_CP_AHB_ERROR_HALT:
-		err = "ringbuffer AHB error interrupt";
-		break;
-	case A3XX_INT_MISC_HANG_DETECT:
-		err = "MISC: GPU hang detected";
-		break;
 	case A3XX_INT_UCHE_OOB_ACCESS:
 		err = "UCHE:  Out of bounds access";
 		break;
 	}
 
-	KGSL_DRV_CRIT(device, "%s\n", err);
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+	/*
+	 * Limit error interrupt reporting to prevent
+	 * kernel logs causing watchdog timeout
+	 */
+	if (!__ratelimit(&ratelimit_state))
+		KGSL_DRV_CRIT(device, "%s\n", err);
 }
 
 static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
@@ -3101,116 +3087,47 @@
 }
 
 /**
- * struct a3xx_perfcounter_register - Define a performance counter register
- * @load_bit: the bit to set in RBBM_LOAD_CMD0/RBBM_LOAD_CMD1 to force the RBBM
- * to load the reset value into the appropriate counter
- * @select: The dword offset of the register to write the selected
- * countable into
+ * a3xx_fatal_err_callback -  Routine for GPU fatal interrupts
+ * @adreno_dev: adreno device ptr
+ * @bit: interrupt bit
  */
+static void a3xx_fatal_err_callback(struct adreno_device *adreno_dev, int bit)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	const char *err = "";
 
-struct a3xx_perfcounter_register {
-	unsigned int load_bit;
-	unsigned int select;
-};
+	switch (bit) {
+	case A3XX_INT_CP_OPCODE_ERROR:
+		err = "ringbuffer opcode error interrupt";
+		break;
+	case A3XX_INT_CP_RESERVED_BIT_ERROR:
+		err = "ringbuffer reserved bit error interrupt";
+		break;
+	case A3XX_INT_CP_T0_PACKET_IN_IB:
+		err = "ringbuffer TO packet in IB interrupt";
+		break;
+	case A3XX_INT_CP_HW_FAULT:
+		err = "ringbuffer hardware fault";
+		break;
+	case A3XX_INT_CP_REG_PROTECT_FAULT:
+		err = "ringbuffer protected mode error interrupt";
+		break;
+	case A3XX_INT_CP_AHB_ERROR_HALT:
+		err = "ringbuffer AHB error interrupt";
+		break;
+	case A3XX_INT_MISC_HANG_DETECT:
+		if (!adreno_dev->hang_intr_en)
+			return;
+		err = "stall interrupt";
+		break;
+	}
 
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_cp[] = {
-	{ 0, A3XX_CP_PERFCOUNTER_SELECT },
-};
+	KGSL_DRV_CRIT(device, "%s\n", err);
+	if ((!device->mmu.fault) &&
+		(adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE))
+		adreno_fatal_err_work(adreno_dev);
+}
 
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rbbm[] = {
-	{ 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
-	{ 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_pc[] = {
-	{ 3, A3XX_PC_PERFCOUNTER0_SELECT },
-	{ 4, A3XX_PC_PERFCOUNTER1_SELECT },
-	{ 5, A3XX_PC_PERFCOUNTER2_SELECT },
-	{ 6, A3XX_PC_PERFCOUNTER3_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vfd[] = {
-	{ 7, A3XX_VFD_PERFCOUNTER0_SELECT },
-	{ 8, A3XX_VFD_PERFCOUNTER1_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_hlsq[] = {
-	{ 9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
-	{ 10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
-	{ 11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
-	{ 12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
-	{ 13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
-	{ 14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vpc[] = {
-	{ 15, A3XX_VPC_PERFCOUNTER0_SELECT },
-	{ 16, A3XX_VPC_PERFCOUNTER1_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tse[] = {
-	{ 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
-	{ 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_ras[] = {
-	{ 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
-	{ 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_uche[] = {
-	{ 21, A3XX_UCHE_PERFCOUNTER0_SELECT },
-	{ 22, A3XX_UCHE_PERFCOUNTER1_SELECT },
-	{ 23, A3XX_UCHE_PERFCOUNTER2_SELECT },
-	{ 24, A3XX_UCHE_PERFCOUNTER3_SELECT },
-	{ 25, A3XX_UCHE_PERFCOUNTER4_SELECT },
-	{ 26, A3XX_UCHE_PERFCOUNTER5_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tp[] = {
-	{ 27, A3XX_TP_PERFCOUNTER0_SELECT },
-	{ 28, A3XX_TP_PERFCOUNTER1_SELECT },
-	{ 29, A3XX_TP_PERFCOUNTER2_SELECT },
-	{ 30, A3XX_TP_PERFCOUNTER3_SELECT },
-	{ 31, A3XX_TP_PERFCOUNTER4_SELECT },
-	{ 32, A3XX_TP_PERFCOUNTER5_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_sp[] = {
-	{ 33, A3XX_SP_PERFCOUNTER0_SELECT },
-	{ 34, A3XX_SP_PERFCOUNTER1_SELECT },
-	{ 35, A3XX_SP_PERFCOUNTER2_SELECT },
-	{ 36, A3XX_SP_PERFCOUNTER3_SELECT },
-	{ 37, A3XX_SP_PERFCOUNTER4_SELECT },
-	{ 38, A3XX_SP_PERFCOUNTER5_SELECT },
-	{ 39, A3XX_SP_PERFCOUNTER6_SELECT },
-	{ 40, A3XX_SP_PERFCOUNTER7_SELECT },
-};
-
-static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rb[] = {
-	{ 41, A3XX_RB_PERFCOUNTER0_SELECT },
-	{ 42, A3XX_RB_PERFCOUNTER1_SELECT },
-};
-
-#define REGCOUNTER_GROUP(_x) { (_x), ARRAY_SIZE((_x)) }
-
-static struct {
-	struct a3xx_perfcounter_register *regs;
-	int count;
-} a3xx_perfcounter_reglist[] = {
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_cp),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_rbbm),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_pc),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_vfd),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_hlsq),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_vpc),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_tse),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_ras),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_uche),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_tp),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_sp),
-	REGCOUNTER_GROUP(a3xx_perfcounter_reg_rb),
-};
 
 static void a3xx_perfcounter_enable_pwr(struct kgsl_device *device,
 	unsigned int countable)
@@ -3309,7 +3226,7 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int val = 0;
-	struct a3xx_perfcounter_register *reg;
+	struct adreno_perfcount_register *reg;
 
 	/* Special cases */
 	if (group == KGSL_PERFCOUNTER_GROUP_PWR)
@@ -3319,13 +3236,14 @@
 	else if (group == KGSL_PERFCOUNTER_GROUP_VBIF_PWR)
 		return a3xx_perfcounter_enable_vbif_pwr(device, countable);
 
-	if (group >= ARRAY_SIZE(a3xx_perfcounter_reglist))
+	if (group >= adreno_dev->gpudev->perfcounters->group_count)
 		return;
 
-	if (counter >= a3xx_perfcounter_reglist[group].count)
+	if (counter >=
+		adreno_dev->gpudev->perfcounters->groups[group].reg_count)
 		return;
 
-	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+	reg = &(adreno_dev->gpudev->perfcounters->groups[group].regs[counter]);
 
 	/* Select the desired perfcounter */
 	kgsl_regwrite(device, reg->select, countable);
@@ -3340,27 +3258,29 @@
 }
 
 static uint64_t a3xx_perfcounter_read(struct adreno_device *adreno_dev,
-	unsigned int group, unsigned int counter,
-	unsigned int offset)
+	unsigned int group, unsigned int counter)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	struct a3xx_perfcounter_register *reg = NULL;
+	struct adreno_perfcount_register *reg;
 	unsigned int lo = 0, hi = 0;
 	unsigned int val;
+	unsigned int offset;
 
-	if (group >= ARRAY_SIZE(a3xx_perfcounter_reglist))
+	if (group >= adreno_dev->gpudev->perfcounters->group_count)
 		return 0;
 
-	if (counter >= a3xx_perfcounter_reglist[group].count)
+	if (counter >=
+		adreno_dev->gpudev->perfcounters->groups[group].reg_count)
 		return 0;
 
-	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+	reg = &(adreno_dev->gpudev->perfcounters->groups[group].regs[counter]);
 
 	/* Freeze the counter */
 	kgsl_regread(device, A3XX_RBBM_PERFCTR_CTL, &val);
 	val &= ~reg->load_bit;
 	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
 
+	offset = reg->offset;
 	/* Read the values */
 	kgsl_regread(device, offset, &lo);
 	kgsl_regread(device, offset + 1, &hi);
@@ -3372,6 +3292,136 @@
 	return (((uint64_t) hi) << 32) | lo;
 }
 
+/*
+ * values cannot be loaded into physical performance
+ * counters belonging to these groups.
+ */
+static inline int loadable_perfcounter_group(unsigned int groupid)
+{
+	return ((groupid == KGSL_PERFCOUNTER_GROUP_VBIF_PWR) ||
+		(groupid == KGSL_PERFCOUNTER_GROUP_VBIF) ||
+		(groupid == KGSL_PERFCOUNTER_GROUP_PWR)) ? 0 : 1;
+}
+
+/*
+ * Return true if the countable is used and not broken
+ */
+static inline int active_countable(unsigned int countable)
+{
+	return ((countable != KGSL_PERFCOUNTER_NOT_USED) &&
+		(countable != KGSL_PERFCOUNTER_BROKEN));
+}
+
+/**
+ * a3xx_perfcounter_save() - Save the physical performance counter values
+ * @adreno_dev -  Adreno device whose registers need to be saved
+ *
+ * Read all the physical performance counter's values and save them
+ * before GPU power collapse.
+ */
+static void a3xx_perfcounter_save(struct adreno_device *adreno_dev)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int regid, groupid;
+
+	for (groupid = 0; groupid < counters->group_count; groupid++) {
+		if (!loadable_perfcounter_group(groupid))
+			continue;
+
+		group = &(counters->groups[groupid]);
+
+		/* group/counter iterator */
+		for (regid = 0; regid < group->reg_count; regid++) {
+			if (!active_countable(group->regs[regid].countable))
+				continue;
+
+			group->regs[regid].value =
+				adreno_dev->gpudev->perfcounter_read(
+				adreno_dev, groupid, regid);
+		}
+	}
+}
+
+/**
+ * a3xx_perfcounter_write() - Write the physical performance counter values.
+ * @adreno_dev -  Adreno device whose registers are to be written to.
+ * @group - group to which the physical counter belongs to.
+ * @counter - register id of the physical counter to which the value is
+ *		written to.
+ *
+ * This function loads the 64 bit saved value into the particular physical
+ * counter by enabling the corresponding bit in A3XX_RBBM_PERFCTR_LOAD_CMD*
+ * register.
+ */
+static void a3xx_perfcounter_write(struct adreno_device *adreno_dev,
+				unsigned int group, unsigned int counter)
+{
+	struct kgsl_device *device = &(adreno_dev->dev);
+	struct adreno_perfcount_register *reg;
+	unsigned int val;
+
+	reg = &(adreno_dev->gpudev->perfcounters->groups[group].regs[counter]);
+
+	/* Clear the load cmd registers */
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, 0);
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, 0);
+
+	/* Write the saved value to PERFCTR_LOAD_VALUE* registers. */
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_VALUE_LO,
+			(uint32_t)reg->value);
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_VALUE_HI,
+			(uint32_t)(reg->value >> 32));
+
+	/*
+	 * Set the load bit in PERFCTR_LOAD_CMD for the physical counter
+	 * we want to restore. The value in PERFCTR_LOAD_VALUE* is loaded
+	 * into the corresponding physical counter.
+	 */
+	if (reg->load_bit < 32)	{
+		val = 1 << reg->load_bit;
+		kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+	} else {
+		val  = 1 << (reg->load_bit - 32);
+		kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+	}
+}
+
+/**
+ * a3xx_perfcounter_restore() - Restore the physical performance counter values.
+ * @adreno_dev -  Adreno device whose registers are to be restored.
+ *
+ * This function together with a3xx_perfcounter_save make sure that performance
+ * counters are coherent across GPU power collapse.
+ */
+static void a3xx_perfcounter_restore(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int regid, groupid;
+
+	for (groupid = 0; groupid < counters->group_count; groupid++) {
+		if (!loadable_perfcounter_group(groupid))
+			continue;
+
+		group = &(counters->groups[groupid]);
+
+		/* group/counter iterator */
+		for (regid = 0; regid < group->reg_count; regid++) {
+			if (!active_countable(group->regs[regid].countable))
+				continue;
+
+			a3xx_perfcounter_write(adreno_dev, groupid, regid);
+		}
+	}
+
+	/* Clear the load cmd registers */
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, 0);
+	kgsl_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, 0);
+
+}
+
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
 
 #define A3XX_INT_MASK \
@@ -3399,23 +3449,25 @@
 	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 5 - RBBM_ATB_BUS_OVERFLOW */
 	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 6 - RBBM_VFD_ERROR */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 7 - CP_SW */
-	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 8 - CP_T0_PACKET_IN_IB */
-	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 9 - CP_OPCODE_ERROR */
-	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 10 - CP_RESERVED_BIT_ERROR */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),/* 8 - CP_T0_PACKET_IN_IB */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),/* 9 - CP_OPCODE_ERROR */
+	/* 10 - CP_RESERVED_BIT_ERROR */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),
 	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 11 - CP_HW_FAULT */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 12 - CP_DMA */
 	A3XX_IRQ_CALLBACK(a3xx_cp_callback),   /* 13 - CP_IB2_INT */
 	A3XX_IRQ_CALLBACK(a3xx_cp_callback),   /* 14 - CP_IB1_INT */
 	A3XX_IRQ_CALLBACK(a3xx_cp_callback),   /* 15 - CP_RB_INT */
-	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 16 - CP_REG_PROTECT_FAULT */
+	/* 16 - CP_REG_PROTECT_FAULT */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),
 	A3XX_IRQ_CALLBACK(NULL),	       /* 17 - CP_RB_DONE_TS */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 18 - CP_VS_DONE_TS */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 19 - CP_PS_DONE_TS */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 20 - CP_CACHE_FLUSH_TS */
-	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 21 - CP_AHB_ERROR_FAULT */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),/* 21 - CP_AHB_ERROR_FAULT */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 22 - Unused */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 23 - Unused */
-	A3XX_IRQ_CALLBACK(NULL),	       /* 24 - MISC_HANG_DETECT */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),/* 24 - MISC_HANG_DETECT */
 	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 25 - UCHE_OOB_ACCESS */
 	/* 26 to 31 - Unused */
 };
@@ -3451,14 +3503,27 @@
 	return ret;
 }
 
-static void a3xx_irq_control(struct adreno_device *adreno_dev, int state)
+/**
+ * a3xx_irq_init() -  Routine to init a3xx irq
+ * @adreno_dev: adreno device ptr
+ */
+static void a3xx_irq_init(struct adreno_device *adreno_dev)
+{
+	if (adreno_hang_intr_supported(adreno_dev)) {
+		adreno_dev->intr_mask = (A3XX_INT_MASK |
+			(1 << A3XX_INT_MISC_HANG_DETECT));
+		adreno_dev->hang_intr_en = 1;
+	} else
+		adreno_dev->intr_mask = A3XX_INT_MASK;
+
+}
+
+static void a3xx_irq_control(struct adreno_device *adreno_dev,
+							 unsigned int mask)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (state)
-		kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
-	else
-		kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
+	kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, mask);
 }
 
 static unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev)
@@ -3624,118 +3689,160 @@
  */
 
 static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_CP_0_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_CP_0_LO,
+		0, A3XX_CP_PERFCOUNTER_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO,
+		1, A3XX_RBBM_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO,
+		2, A3XX_RBBM_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_1_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_2_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_3_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_0_LO,
+		3, A3XX_PC_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_1_LO,
+		4, A3XX_PC_PERFCOUNTER1_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_2_LO,
+		5, A3XX_PC_PERFCOUNTER2_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PC_3_LO,
+		6, A3XX_PC_PERFCOUNTER3_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_0_LO,
+		7, A3XX_VFD_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VFD_1_LO,
+		8, A3XX_VFD_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO,
+		9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO,
+		10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO,
+		11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO,
+		12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO,
+		13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO,
+		14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_0_LO,
+		15, A3XX_VPC_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_VPC_1_LO,
+		16, A3XX_VPC_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_0_LO,
+		17, A3XX_GRAS_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TSE_1_LO,
+		18, A3XX_GRAS_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_0_LO,
+		19, A3XX_GRAS_PERFCOUNTER2_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RAS_1_LO,
+		20, A3XX_GRAS_PERFCOUNTER3_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO,
+		21, A3XX_UCHE_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO,
+		22, A3XX_UCHE_PERFCOUNTER1_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO,
+		23, A3XX_UCHE_PERFCOUNTER2_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO,
+		24, A3XX_UCHE_PERFCOUNTER3_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO,
+		25, A3XX_UCHE_PERFCOUNTER4_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO,
+		26, A3XX_UCHE_PERFCOUNTER5_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_1_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_2_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_3_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_4_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_5_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_0_LO,
+		27, A3XX_TP_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_1_LO,
+		28, A3XX_TP_PERFCOUNTER1_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_2_LO,
+		29, A3XX_TP_PERFCOUNTER2_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_3_LO,
+		30, A3XX_TP_PERFCOUNTER3_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_4_LO,
+		31, A3XX_TP_PERFCOUNTER4_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_TP_5_LO,
+		32, A3XX_TP_PERFCOUNTER5_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_1_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_2_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_3_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_4_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_5_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_6_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_7_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_0_LO,
+		33, A3XX_SP_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_1_LO,
+		34, A3XX_SP_PERFCOUNTER1_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_2_LO,
+		35, A3XX_SP_PERFCOUNTER2_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_3_LO,
+		36, A3XX_SP_PERFCOUNTER3_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_4_LO,
+		37, A3XX_SP_PERFCOUNTER4_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_5_LO,
+		38, A3XX_SP_PERFCOUNTER5_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_6_LO,
+		39, A3XX_SP_PERFCOUNTER6_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_SP_7_LO,
+		40, A3XX_SP_PERFCOUNTER7_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_0_LO,
+		41, A3XX_RB_PERFCOUNTER0_SELECT },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_RB_1_LO,
+		42, A3XX_RB_PERFCOUNTER1_SELECT },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_0_LO,
+		-1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_RBBM_PERFCTR_PWR_1_LO,
+		-1, 0 },
 };
 
 static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT0_LO, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_CNT1_LO, -1, 0 },
 };
 static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = {
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO },
-	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT0_LO, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT1_LO, -1, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0, A3XX_VBIF_PERF_PWR_CNT2_LO, -1, 0 },
 };
 
-#define A3XX_PERFCOUNTER_GROUP(name) { a3xx_perfcounters_##name, \
-	ARRAY_SIZE(a3xx_perfcounters_##name), __stringify(name) }
-
 static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
-	A3XX_PERFCOUNTER_GROUP(cp),
-	A3XX_PERFCOUNTER_GROUP(rbbm),
-	A3XX_PERFCOUNTER_GROUP(pc),
-	A3XX_PERFCOUNTER_GROUP(vfd),
-	A3XX_PERFCOUNTER_GROUP(hlsq),
-	A3XX_PERFCOUNTER_GROUP(vpc),
-	A3XX_PERFCOUNTER_GROUP(tse),
-	A3XX_PERFCOUNTER_GROUP(ras),
-	A3XX_PERFCOUNTER_GROUP(uche),
-	A3XX_PERFCOUNTER_GROUP(tp),
-	A3XX_PERFCOUNTER_GROUP(sp),
-	A3XX_PERFCOUNTER_GROUP(rb),
-	A3XX_PERFCOUNTER_GROUP(pwr),
-	A3XX_PERFCOUNTER_GROUP(vbif),
-	A3XX_PERFCOUNTER_GROUP(vbif_pwr),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, cp),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, rbbm),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, pc),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, vfd),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, hlsq),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, vpc),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, tse),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, ras),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, uche),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, tp),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, sp),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, rb),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, pwr),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, vbif),
+	ADRENO_PERFCOUNTER_GROUP(a3xx, vbif_pwr),
 };
 
 static struct adreno_perfcounters a3xx_perfcounters = {
@@ -3857,8 +3964,11 @@
 
 	/* Turn on hang detection - this spews a lot of useful information
 	 * into the RBBM registers on a hang */
-
-	kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+	if (adreno_is_a330v2(adreno_dev))
+		kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+			(1 << 31) | 0xFFFF);
+	else
+		kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
 			(1 << 16) | 0xFFF);
 
 	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
@@ -4257,14 +4367,18 @@
 	.ctxt_draw_workaround = NULL,
 	.rb_init = a3xx_rb_init,
 	.perfcounter_init = a3xx_perfcounter_init,
+	.perfcounter_save = a3xx_perfcounter_save,
+	.perfcounter_restore = a3xx_perfcounter_restore,
 	.irq_control = a3xx_irq_control,
 	.irq_handler = a3xx_irq_handler,
 	.irq_pending = a3xx_irq_pending,
+	.irq_init = a3xx_irq_init,
 	.busy_cycles = a3xx_busy_cycles,
 	.start = a3xx_start,
 	.snapshot = a3xx_snapshot,
 	.perfcounter_enable = a3xx_perfcounter_enable,
 	.perfcounter_read = a3xx_perfcounter_read,
+	.perfcounter_write = a3xx_perfcounter_write,
 	.coresight_enable = a3xx_coresight_enable,
 	.coresight_disable = a3xx_coresight_disable,
 	.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 32dbd51..b8c451e 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -406,9 +406,11 @@
 	const uint32_t *rb_vaddr;
 	int num_item = 0;
 	int read_idx, write_idx;
-	unsigned int ts_processed = 0xdeaddead;
+	unsigned int ts_processed = 0;
+	unsigned int curr_global_ts = 0;
 	struct kgsl_context *context;
 	unsigned int context_id;
+	static char pid_name[TASK_COMM_LEN] = "unknown";
 	unsigned int rbbm_status;
 
 	static struct ib_list ib_list;
@@ -459,8 +461,36 @@
 		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
 		&cp_ib2_bufsz);
 
+	kgsl_sharedmem_readl(&device->memstore,
+			(unsigned int *) &context_id,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+				current_context));
+	context = idr_find(&device->context_idr, context_id);
+	if (context)
+		ts_processed = kgsl_readtimestamp(device, context,
+					  KGSL_TIMESTAMP_RETIRED);
+
 	/* If postmortem dump is not enabled, dump minimal set and return */
 	if (!device->pm_dump_enable) {
+		struct task_struct *task = NULL;
+		/* Read the current global timestamp here */
+		kgsl_sharedmem_readl(&device->memstore,
+			&curr_global_ts,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+
+		if (context)
+			task = find_task_by_vpid(context->pid);
+
+		if (task)
+			get_task_comm(pid_name, task);
+
+		KGSL_LOG_DUMP(device,
+			"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
+			" on global ts %d\n", pid_name,
+			context ? context->id : 0,
+			ts_processed ? ts_processed + 1 : 0,
+			curr_global_ts ? curr_global_ts + 1 : 0);
 
 		KGSL_LOG_DUMP(device,
 			"STATUS %08X | IB1:%08X/%08X | IB2: %08X/%08X"
@@ -471,19 +501,10 @@
 		return 0;
 	}
 
-	kgsl_sharedmem_readl(&device->memstore,
-			(unsigned int *) &context_id,
-			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-				current_context));
-
-	context = kgsl_context_get(device, context_id);
-
-	if (context) {
-		ts_processed = kgsl_readtimestamp(device, context,
-						  KGSL_TIMESTAMP_RETIRED);
+	if (ts_processed)
 		KGSL_LOG_DUMP(device, "FT CTXT: %d  TIMESTM RTRD: %08X\n",
 				context->id, ts_processed);
-	} else
+	else
 		KGSL_LOG_DUMP(device, "BAD CTXT: %d\n", context_id);
 
 	kgsl_context_put(context);
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 896b6e8..7d9d63f 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -597,7 +597,7 @@
 static char *_parse_next_assignment(struct adreno_device *adreno_dev,
 		char *str, int *groupid, int *countable, bool *remove)
 {
-	char *groupid_str, *countable_str;
+	char *groupid_str, *countable_str, *next_str = NULL;
 	int ret;
 
 	*groupid = -EINVAL;
@@ -635,8 +635,15 @@
 	if (countable_str == str)
 		return NULL;
 
-	*str = '\0';
-	str++;
+	/*
+	 * If we have reached the end of the original string then make sure we
+	 * return NULL from this function or we could accidently overrun
+	 */
+
+	if (*str != '\0') {
+		*str = '\0';
+		next_str = str + 1;
+	}
 
 	/* set results */
 	*groupid = adreno_perfcounter_get_groupid(adreno_dev,
@@ -647,7 +654,7 @@
 	if (ret)
 		return NULL;
 
-	return str;
+	return next_str;
 }
 
 static ssize_t profile_assignments_write(struct file *filep,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ceff923..8871a23 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -69,6 +69,7 @@
 	unsigned long wait_time_part;
 	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 	unsigned int rptr;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
 
 	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
@@ -107,17 +108,16 @@
 
 		/* Dont wait for timeout, detect hang faster.
 		 */
+
+		if (kgsl_atomic_read(&adreno_dev->hang_intr_set))
+			goto hang_detected;
+
 		if (time_after(jiffies, wait_time_part)) {
 			wait_time_part = jiffies +
 				msecs_to_jiffies(KGSL_TIMEOUT_PART);
-			if ((adreno_ft_detect(rb->device,
-						prev_reg_val))){
-				KGSL_DRV_ERR(rb->device,
-				"Hang detected while waiting for freespace in"
-				"ringbuffer rptr: 0x%x, wptr: 0x%x\n",
-				rptr, rb->wptr);
-				goto err;
-			}
+
+			if ((adreno_ft_detect(rb->device, prev_reg_val)))
+				goto hang_detected;
 		}
 
 		if (time_after(jiffies, wait_time)) {
@@ -129,6 +129,12 @@
 
 		continue;
 
+hang_detected:
+		KGSL_DRV_ERR(rb->device,
+			"Hang detected while waiting for freespace in"
+			"ringbuffer rptr: 0x%x, wptr: 0x%x\n",
+			rptr, rb->wptr);
+
 err:
 		if (!adreno_dump_and_exec_ft(rb->device)) {
 			if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
@@ -1073,7 +1079,7 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	unsigned int *link = 0;
 	unsigned int *cmds;
-	unsigned int i;
+	unsigned int i, cmdflags;
 	struct adreno_context *drawctxt = NULL;
 	unsigned int start_index = 0;
 	int ret;
@@ -1095,6 +1101,8 @@
 		goto done;
 	}
 
+	cmdflags = (flags & KGSL_CMD_FLAGS_EOF);
+
 	/* process any profiling results that are available into the log_buf */
 	adreno_profile_process_results(device);
 
@@ -1161,7 +1169,7 @@
 
 	if (test_and_clear_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv) &&
 		test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
-			flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
+			cmdflags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
 
 	if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
 		if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
@@ -1178,7 +1186,7 @@
 
 	ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
 					drawctxt,
-					flags,
+					cmdflags,
 					&link[0], (cmds - link));
 	if (ret)
 		goto done;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7da0811..6cd1f68 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -110,6 +110,29 @@
 }
 
 /**
+ * kgsl_hang_intr_work() - GPU hang interrupt work
+ * @dev: device ptr
+ *
+ * This function is called when GPU hang interrupt happens. In
+ * this fuction we check the device state and trigger fault
+ * tolerance.
+ */
+void kgsl_hang_intr_work(struct work_struct *work)
+{
+	struct kgsl_device *device = container_of(work, struct kgsl_device,
+							hang_intr_ws);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/* If hang_intr_set is set, turn it off and trigger FT */
+	mutex_lock(&device->mutex);
+	if ((device->state == KGSL_STATE_ACTIVE) &&
+		(atomic_cmpxchg(&adreno_dev->hang_intr_set, 1, 0)))
+			adreno_dump_and_exec_ft(device);
+	mutex_unlock(&device->mutex);
+
+}
+
+/**
  * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
  * device: KGSL device
  * id: ID of the context submitting the command
@@ -909,6 +932,9 @@
 
 	private = kgsl_find_process_private(cur_dev_priv);
 
+	if (!private)
+		return NULL;
+
 	mutex_lock(&private->process_private_mutex);
 
 	if (test_bit(KGSL_PROCESS_INIT, &private->priv))
@@ -3049,7 +3075,7 @@
 static inline bool
 mmap_range_valid(unsigned long addr, unsigned long len)
 {
-	return (addr + len) > addr && (addr + len) < TASK_SIZE;
+	return ((ULONG_MAX - addr) > len) && ((addr + len) < TASK_SIZE);
 }
 
 static unsigned long
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 8d390a9..42d3b3e 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -205,10 +205,25 @@
 #define MMU_CONFIG 1
 #endif
 
+void kgsl_hang_intr_work(struct work_struct *work);
 void kgsl_hang_check(struct work_struct *work);
 void kgsl_mem_entry_destroy(struct kref *kref);
 int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
 
+static inline void kgsl_atomic_set(atomic_t *addr, unsigned int val)
+{
+	atomic_set(addr, val);
+	/* make sure above write is posted */
+	wmb();
+}
+
+static inline int kgsl_atomic_read(atomic_t *addr)
+{
+	/* make sure below read is read from memory */
+	rmb();
+	return atomic_read(addr);
+}
+
 struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
 		phys_addr_t ptbase, unsigned int gpuaddr, unsigned int size);
 
@@ -267,7 +282,7 @@
 		size = 1;
 
 	/* don't overflow */
-	if ((gpuaddr + size) < gpuaddr)
+	if (size > UINT_MAX - gpuaddr)
 		return 0;
 
 	if (gpuaddr >= memdesc->gpuaddr &&
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0b5fe52..40e4e39 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -110,7 +110,7 @@
 		struct kgsl_pagetable *pagetable);
 	void (*power_stats)(struct kgsl_device *device,
 		struct kgsl_power_stats *stats);
-	void (*irqctrl)(struct kgsl_device *device, int state);
+	void (*irqctrl)(struct kgsl_device *device, unsigned int mask);
 	unsigned int (*gpuid)(struct kgsl_device *device, unsigned int *chipid);
 	void * (*snapshot)(struct kgsl_device *device, void *snapshot,
 		int *remain, int hang);
@@ -191,6 +191,7 @@
 	const struct kgsl_functable *ftbl;
 	struct work_struct idle_check_ws;
 	struct work_struct hang_check_ws;
+	struct work_struct hang_intr_ws;
 	struct timer_list idle_timer;
 	struct timer_list hang_timer;
 	struct kgsl_pwrctrl pwrctrl;
@@ -259,6 +260,8 @@
 			kgsl_idle_check),\
 	.hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\
 			kgsl_hang_check),\
+	.hang_intr_ws = __WORK_INITIALIZER((_dev).hang_intr_ws,\
+			kgsl_hang_intr_work),\
 	.ts_expired_ws  = __WORK_INITIALIZER((_dev).ts_expired_ws,\
 			kgsl_process_events),\
 	.context_idr = IDR_INIT((_dev).context_idr),\
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index a06ebbf..acb3b17 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -344,6 +344,9 @@
 	device = mmu->device;
 	adreno_dev = ADRENO_DEVICE(device);
 
+	mmu->fault = 1;
+	iommu_dev->fault = 1;
+
 	ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
 					iommu_dev->ctx_id, TTBR0);
 
@@ -394,9 +397,6 @@
 
 	}
 
-	mmu->fault = 1;
-	iommu_dev->fault = 1;
-
 	kgsl_sharedmem_readl(&device->memstore, &curr_context_id,
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
 
@@ -425,8 +425,10 @@
 	 * the GPU and trigger a snapshot. To stall the transaction return
 	 * EBUSY error.
 	 */
-	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) {
+		adreno_fatal_err_work(adreno_dev);
 		ret = -EBUSY;
+	}
 done:
 	return ret;
 }
@@ -1803,6 +1805,10 @@
 						iommu_unit,
 						iommu_unit->dev[j].ctx_id,
 						RESUME, 1);
+					KGSL_IOMMU_SET_CTX_REG(iommu,
+						iommu_unit,
+						iommu_unit->dev[j].ctx_id,
+						FSR, 0);
 					_iommu_unlock(iommu);
 					iommu_unit->dev[j].fault = 0;
 				}
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 103a751..ccb2e00 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -927,11 +927,11 @@
 	}
 }
 
-static void z180_irqctrl(struct kgsl_device *device, int state)
+static void z180_irqctrl(struct kgsl_device *device, unsigned int mask)
 {
 	/* Control interrupts for Z180 and the Z180 MMU */
 
-	if (state) {
+	if (mask) {
 		z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 3);
 		z180_regwrite(device, MH_INTERRUPT_MASK,
 			kgsl_mmu_get_int_mask());
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index 937bf6c..b753d55 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -190,6 +190,7 @@
 
 struct stk3x1x_data {
 	struct i2c_client *client;
+	struct stk3x1x_platform_data *pdata;
 #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
     int32_t irq;
     struct work_struct stk_work;
@@ -257,6 +258,7 @@
 static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h);
 static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l);
 static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h);
+static int stk3x1x_device_ctl(struct stk3x1x_data *ps_data, bool enable);
 //static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset);
 
 inline uint32_t stk_alscode2lux(struct stk3x1x_data *ps_data, uint32_t alscode)
@@ -600,6 +602,12 @@
 	if(curr_ps_enable == enable)
 		return 0;
 
+	if (enable) {
+		ret = stk3x1x_device_ctl(ps_data, enable);
+		if (ret)
+			return ret;
+	}
+
     ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
     if (ret < 0)
     {
@@ -662,6 +670,12 @@
 #endif
 		ps_data->ps_enabled = false;
 	}
+	if (!enable) {
+		ret = stk3x1x_device_ctl(ps_data, enable);
+		if (ret)
+			return ret;
+	}
+
 	return ret;
 }
 
@@ -674,6 +688,11 @@
 	if(curr_als_enable == enable)
 		return 0;
 
+	if (enable) {
+		ret = stk3x1x_device_ctl(ps_data, enable);
+		if (ret)
+			return ret;
+	}
 #ifndef STK_POLL_ALS
     if (enable)
 	{
@@ -724,6 +743,12 @@
 			disable_irq(ps_data->irq);
 #endif
 	}
+	if (!enable) {
+		ret = stk3x1x_device_ctl(ps_data, enable);
+		if (ret)
+			return ret;
+	}
+
     return ret;
 }
 
@@ -1817,11 +1842,6 @@
 	int32_t ret;
 	struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
 
-	mutex_lock(&ps_data->io_lock);
-	ps_data->als_enabled = false;
-	ps_data->ps_enabled = false;
-	mutex_unlock(&ps_data->io_lock);
-
 	ret = stk3x1x_software_reset(ps_data);
 	if(ret < 0)
 		return ret;
@@ -1946,7 +1966,7 @@
 }
 #endif	//#ifdef CONFIG_HAS_EARLYSUSPEND
 
-static int stk3x1x_power_on(struct stk3x1x_data *data, bool on)
+static int stk3x1x_power_ctl(struct stk3x1x_data *data, bool on)
 {
 	int ret = 0;
 
@@ -1963,7 +1983,11 @@
 			dev_err(&data->client->dev,
 				"Regulator vio disable failed ret=%d\n", ret);
 			regulator_enable(data->vdd);
+			return ret;
 		}
+		data->power_enabled = on;
+		dev_dbg(&data->client->dev, "stk3x1x_power_ctl on=%d\n",
+				on);
 	} else if (on && !data->power_enabled) {
 
 		ret = regulator_enable(data->vdd);
@@ -1978,7 +2002,11 @@
 			dev_err(&data->client->dev,
 				"Regulator vio enable failed ret=%d\n", ret);
 			regulator_disable(data->vdd);
+			return ret;
 		}
+		data->power_enabled = on;
+		dev_dbg(&data->client->dev, "stk3x1x_power_ctl on=%d\n",
+				on);
 	} else {
 		dev_warn(&data->client->dev,
 				"Power on=%d. enabled=%d\n",
@@ -2057,6 +2085,43 @@
 	return ret;
 }
 
+static int stk3x1x_device_ctl(struct stk3x1x_data *ps_data, bool enable)
+{
+	int ret;
+	struct device *dev = &ps_data->client->dev;
+
+	if (enable && !ps_data->power_enabled) {
+		ret = stk3x1x_power_ctl(ps_data, true);
+		if (ret) {
+			dev_err(dev, "Failed to enable device power\n");
+			goto err_exit;
+		}
+		ret = stk3x1x_init_all_setting(ps_data->client, ps_data->pdata);
+		if (ret < 0) {
+			stk3x1x_power_ctl(ps_data, false);
+			dev_err(dev, "Failed to re-init device setting\n");
+			goto err_exit;
+		}
+	} else if (!enable && ps_data->power_enabled) {
+		if (!ps_data->als_enabled && !ps_data->ps_enabled) {
+			ret = stk3x1x_power_ctl(ps_data, false);
+			if (ret) {
+				dev_err(dev, "Failed to disable device power\n");
+				goto err_exit;
+			}
+		} else {
+			dev_dbg(dev, "device control: als_enabled=%d, ps_enabled=%d\n",
+				ps_data->als_enabled, ps_data->ps_enabled);
+		}
+	} else {
+		dev_dbg(dev, "device control: enable=%d, power_enabled=%d\n",
+			enable, ps_data->power_enabled);
+	}
+	return 0;
+
+err_exit:
+	return ret;
+}
 #ifdef CONFIG_OF
 static int stk3x1x_parse_dt(struct device *dev,
 			struct stk3x1x_platform_data *pdata)
@@ -2205,6 +2270,7 @@
 	ps_data->als_transmittance = plat_data->transmittance;
 	ps_data->int_pin = plat_data->int_pin;
 	ps_data->use_fir = plat_data->use_fir;
+	ps_data->pdata = plat_data;
 
 	if (ps_data->als_transmittance == 0) {
 		dev_err(&client->dev,
@@ -2285,24 +2351,28 @@
 	if (err)
 		goto err_power_init;
 
-	err = stk3x1x_power_on(ps_data, true);
+	err = stk3x1x_power_ctl(ps_data, true);
 	if (err)
 		goto err_power_on;
 
-	err = stk3x1x_init_all_setting(client, plat_data);
-	if(err < 0)
-		goto err_init_all_setting;
+	ps_data->als_enabled = false;
+	ps_data->ps_enabled = false;
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	ps_data->stk_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
 	ps_data->stk_early_suspend.suspend = stk3x1x_early_suspend;
 	ps_data->stk_early_suspend.resume = stk3x1x_late_resume;
 	register_early_suspend(&ps_data->stk_early_suspend);
 #endif
-	printk(KERN_INFO "%s: probe successfully", __func__);
+	/* enable device power only when it is enabled */
+	err = stk3x1x_power_ctl(ps_data, false);
+	if (err)
+		goto err_init_all_setting;
+
+	dev_dbg(&client->dev, "%s: probe successfully", __func__);
 	return 0;
 
 err_init_all_setting:
-	stk3x1x_power_on(ps_data, false);
+	stk3x1x_power_ctl(ps_data, false);
 err_power_on:
 	stk3x1x_power_init(ps_data, false);
 err_power_init:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 4dbe5c1..3731561 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1727,7 +1727,7 @@
 	}
 
 	ret = request_firmware(&fw, fn, dev);
-	if (ret < 0) {
+	if (ret < 0 || !fw) {
 		dev_err(dev, "Unable to open firmware %s\n", fn);
 		goto free_frame;
 	}
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index aa50d44..ef76e69 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -288,7 +288,7 @@
 	struct ft5x06_ts_data *data = dev_id;
 	struct input_dev *ip_dev;
 	int rc, i;
-	u32 id, x, y, pressure, status, num_touches;
+	u32 id, x, y, status, num_touches;
 	u8 reg = 0x00, *buf;
 	bool update_input = false;
 
@@ -329,11 +329,9 @@
 
 		input_mt_slot(ip_dev, id);
 		if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) {
-			pressure = FT_PRESS;
 			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1);
 			input_report_abs(ip_dev, ABS_MT_POSITION_X, x);
 			input_report_abs(ip_dev, ABS_MT_POSITION_Y, y);
-			input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
 		} else {
 			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
 		}
@@ -479,7 +477,7 @@
 		input_mt_slot(data->input_dev, i);
 		input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0);
 	}
-	input_report_key(data->input_dev, BTN_TOUCH, 0);
+	input_mt_report_pointer_emulation(data->input_dev, false);
 	input_sync(data->input_dev);
 
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
@@ -1369,7 +1367,6 @@
 			     pdata->x_max, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
 			     pdata->y_max, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
 
 	err = input_register_device(input_dev);
 	if (err) {
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 4e75971..d21b6c1 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -79,9 +79,12 @@
 	STATUS_DEVICE_FAILURE = 0x03,
 	STATUS_CONFIG_CRC_FAILURE = 0x04,
 	STATUS_FIRMWARE_CRC_FAILURE = 0x05,
-	STATUS_CRC_IN_PROGRESS = 0x06
+	STATUS_CRC_IN_PROGRESS = 0x06,
+	STATUS_UNCONFIGURED = 0x80
 };
 
+#define DEVICE_CONFIGURED 0x1
+
 #define RMI4_VTG_MIN_UV		2700000
 #define RMI4_VTG_MAX_UV		3300000
 #define RMI4_ACTIVE_LOAD_UA	15000
@@ -172,6 +175,20 @@
 	};
 };
 
+struct synaptics_rmi4_f01_device_control_0 {
+	union {
+		struct {
+			unsigned char sleep_mode:2;
+			unsigned char nosleep:1;
+			unsigned char reserved:2;
+			unsigned char charger_input:1;
+			unsigned char report_rate:1;
+			unsigned char configured:1;
+		} __packed;
+		unsigned char data[1];
+	};
+};
+
 struct synaptics_rmi4_f12_query_5 {
 	union {
 		struct {
@@ -2654,8 +2671,6 @@
 				goto err_reset_gpio_dir;
 			}
 
-			gpio_set_value(rmi4_data->board->reset_gpio, 0);
-			usleep(RMI4_GPIO_SLEEP_LOW_US);
 			gpio_set_value(rmi4_data->board->reset_gpio, 1);
 			msleep(rmi4_data->board->reset_delay);
 		} else
@@ -2666,8 +2681,22 @@
 		if (rmi4_data->board->disable_gpios) {
 			if (gpio_is_valid(rmi4_data->board->irq_gpio))
 				gpio_free(rmi4_data->board->irq_gpio);
-			if (gpio_is_valid(rmi4_data->board->reset_gpio))
+			if (gpio_is_valid(rmi4_data->board->reset_gpio)) {
+				/*
+				 * This is intended to save leakage current
+				 * only. Even if the call(gpio_direction_input)
+				 * fails, only leakage current will be more but
+				 * functionality will not be affected.
+				 */
+				retval = gpio_direction_input(rmi4_data->
+							board->reset_gpio);
+				if (retval) {
+					dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio "
+					"[%d]\n", rmi4_data->board->irq_gpio);
+				}
 				gpio_free(rmi4_data->board->reset_gpio);
+			}
 		}
 
 		return 0;
@@ -3088,12 +3117,12 @@
 static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data)
 {
 	int retval;
-	unsigned char device_ctrl;
+	struct synaptics_rmi4_f01_device_control_0 device_ctrl;
 
 	retval = synaptics_rmi4_i2c_read(rmi4_data,
 			rmi4_data->f01_ctrl_base_addr,
-			&device_ctrl,
-			sizeof(device_ctrl));
+			device_ctrl.data,
+			sizeof(device_ctrl.data));
 	if (retval < 0) {
 		dev_err(&(rmi4_data->input_dev->dev),
 				"%s: Failed to enter sleep mode\n",
@@ -3102,13 +3131,13 @@
 		return;
 	}
 
-	device_ctrl = (device_ctrl & ~MASK_3BIT);
-	device_ctrl = (device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP);
+	device_ctrl.sleep_mode = SENSOR_SLEEP;
+	device_ctrl.nosleep = NO_SLEEP_OFF;
 
 	retval = synaptics_rmi4_i2c_write(rmi4_data,
 			rmi4_data->f01_ctrl_base_addr,
-			&device_ctrl,
-			sizeof(device_ctrl));
+			device_ctrl.data,
+			sizeof(device_ctrl.data));
 	if (retval < 0) {
 		dev_err(&(rmi4_data->input_dev->dev),
 				"%s: Failed to enter sleep mode\n",
@@ -3132,12 +3161,12 @@
 static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data)
 {
 	int retval;
-	unsigned char device_ctrl;
+	struct synaptics_rmi4_f01_device_control_0 device_ctrl;
 
 	retval = synaptics_rmi4_i2c_read(rmi4_data,
 			rmi4_data->f01_ctrl_base_addr,
-			&device_ctrl,
-			sizeof(device_ctrl));
+			device_ctrl.data,
+			sizeof(device_ctrl.data));
 	if (retval < 0) {
 		dev_err(&(rmi4_data->input_dev->dev),
 				"%s: Failed to wake from sleep mode\n",
@@ -3146,13 +3175,13 @@
 		return;
 	}
 
-	device_ctrl = (device_ctrl & ~MASK_3BIT);
-	device_ctrl = (device_ctrl | NO_SLEEP_OFF | NORMAL_OPERATION);
+	device_ctrl.sleep_mode = NORMAL_OPERATION;
+	device_ctrl.nosleep = NO_SLEEP_OFF;
 
 	retval = synaptics_rmi4_i2c_write(rmi4_data,
 			rmi4_data->f01_ctrl_base_addr,
-			&device_ctrl,
-			sizeof(device_ctrl));
+			device_ctrl.data,
+			sizeof(device_ctrl.data));
 	if (retval < 0) {
 		dev_err(&(rmi4_data->input_dev->dev),
 				"%s: Failed to wake from sleep mode\n",
@@ -3365,6 +3394,51 @@
 	return retval;
 }
 
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+						*rmi4_data)
+{
+	int retval;
+	struct synaptics_rmi4_f01_device_control_0 device_control;
+	struct synaptics_rmi4_f01_device_status device_status;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			rmi4_data->f01_data_base_addr,
+			device_status.data,
+			sizeof(device_status.data));
+	if (retval < 0) {
+		dev_err(&rmi4_data->i2c_client->dev,
+			"Failed to read device status, rc=%d\n", retval);
+		return retval;
+	}
+
+	if (device_status.unconfigured) {
+		retval = synaptics_rmi4_query_device(rmi4_data);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Failed to query device, rc=%d\n", retval);
+			return retval;
+		}
+
+		retval = synaptics_rmi4_i2c_read(rmi4_data,
+				rmi4_data->f01_ctrl_base_addr,
+				device_control.data,
+				sizeof(device_control.data));
+		if (retval < 0)
+			return retval;
+
+		device_control.configured = DEVICE_CONFIGURED;
+
+		retval = synaptics_rmi4_i2c_write(rmi4_data,
+				rmi4_data->f01_ctrl_base_addr,
+				device_control.data,
+				sizeof(device_control.data));
+		if (retval < 0)
+			return retval;
+	}
+
+	return 0;
+}
+
  /**
  * synaptics_rmi4_suspend()
  *
@@ -3447,24 +3521,29 @@
 		return 0;
 	}
 
+	retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
+	if (retval < 0) {
+		dev_err(dev, "Failed to enter active power mode\n");
+		return retval;
+	}
+
 	if (rmi4_data->board->disable_gpios) {
 		retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
 		if (retval < 0) {
-			dev_err(dev, "failed to put gpios in active state\n");
+			dev_err(dev, "Failed to put gpios in active state\n");
 			return retval;
 		}
 	}
 
-	retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
-	if (retval < 0) {
-		dev_err(dev, "failed to enter active power mode\n");
-		return retval;
-	}
-
 	synaptics_rmi4_sensor_wake(rmi4_data);
 	rmi4_data->touch_stopped = false;
 	synaptics_rmi4_irq_enable(rmi4_data, true);
 
+	retval = synaptics_rmi4_check_configuration(rmi4_data);
+	if (retval < 0) {
+		dev_err(dev, "Failed to check configuration\n");
+		return retval;
+	}
 	rmi4_data->suspended = false;
 
 	return 0;
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index c81aa0ac..84f81bf 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -956,7 +956,8 @@
 			__print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
 		}
 
-		SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
+		if (ret != -EBUSY)
+			SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
 		ret = IRQ_HANDLED;
 	} else
 		ret = IRQ_NONE;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bf59d03..8ae5671 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -25,6 +25,7 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
+#include <linux/delay.h>
 
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
 #define WLED_IDAC_DLY_REG(base, n)	(WLED_MOD_EN_REG(base, n) + 0x01)
@@ -103,6 +104,7 @@
 #define FLASH_LED_TORCH(base)		(base + 0xE4)
 #define FLASH_FAULT_DETECT(base)	(base + 0x51)
 #define FLASH_PERIPHERAL_SUBTYPE(base)	(base + 0x05)
+#define FLASH_CURRENT_RAMP(base)	(base + 0x54)
 
 #define FLASH_MAX_LEVEL			0x4F
 #define TORCH_MAX_LEVEL			0x0F
@@ -121,6 +123,7 @@
 #define FLASH_HW_VREG_OK		0x40
 #define FLASH_VREG_MASK			0xC0
 #define FLASH_STARTUP_DLY_MASK		0x02
+#define FLASH_CURRENT_RAMP_MASK		0xBF
 
 #define FLASH_ENABLE_ALL		0xE0
 #define FLASH_ENABLE_MODULE		0x80
@@ -131,6 +134,7 @@
 #define FLASH_ENABLE_LED_1		0xA0
 #define FLASH_INIT_MASK			0xE0
 #define	FLASH_SELFCHECK_ENABLE		0x80
+#define FLASH_RAMP_STEP_27US		0xBF
 
 #define FLASH_STROBE_SW			0xC0
 #define FLASH_STROBE_HW			0x04
@@ -155,6 +159,9 @@
 #define FLASH_SUBTYPE_DUAL		0x01
 #define FLASH_SUBTYPE_SINGLE		0x02
 
+#define FLASH_RAMP_UP_DELAY_US		1000
+#define FLASH_RAMP_DN_DELAY_US		2160
+
 #define LED_TRIGGER_DEFAULT		"none"
 
 #define RGB_LED_SRC_SEL(base)		(base + 0x45)
@@ -932,22 +939,6 @@
 					rc);
 					goto error_flash_set;
 				}
-
-				/*
-				 * Write 0x80 to MODULE_ENABLE before writing
-				 * 0xE0 in order to avoid a hardware bug caused
-				 * by register value going from 0x00 to 0xE0.
-				 */
-				rc = qpnp_led_masked_write(led,
-					FLASH_ENABLE_CONTROL(led->base),
-					FLASH_ENABLE_MODULE_MASK,
-					FLASH_ENABLE_MODULE);
-				if (rc) {
-					dev_err(&led->spmi_dev->dev,
-						"Enable reg write failed(%d)\n",
-						rc);
-					return rc;
-				}
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -1064,22 +1055,6 @@
 				goto error_flash_set;
 			}
 
-			/*
-			 * Write 0x80 to MODULE_ENABLE before writing
-			 * 0xE0 in order to avoid a hardware bug caused
-			 * by register value going from 0x00 to 0xE0.
-			 */
-			rc = qpnp_led_masked_write(led,
-				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MODULE_MASK,
-				FLASH_ENABLE_MODULE);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"Enable reg write failed(%d)\n",
-					rc);
-				goto error_flash_set;
-			}
-
 			rc = qpnp_led_masked_write(led,
 				led->flash_cfg->current_addr,
 				FLASH_CURRENT_MASK,
@@ -1100,6 +1075,11 @@
 				goto error_flash_set;
 			}
 
+			/*
+			 * Add 1ms delay for bharger enter stable state
+			 */
+			usleep(FLASH_RAMP_UP_DELAY_US);
+
 			if (!led->flash_cfg->strobe_type) {
 				rc = qpnp_led_masked_write(led,
 					FLASH_LED_STROBE_CTRL(led->base),
@@ -1180,6 +1160,12 @@
 				}
 			}
 		} else {
+			/*
+			 * Disable module after ramp down complete for stable
+			 * behavior
+			 */
+			usleep(FLASH_RAMP_DN_DELAY_US);
+
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
 				led->flash_cfg->enable_module &
@@ -2260,7 +2246,7 @@
 
 	/* Disable flash LED module */
 	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-		FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
+		FLASH_ENABLE_MASK, FLASH_DISABLE_ALL);
 	if (rc) {
 		dev_err(&led->spmi_dev->dev,
 			"Enable reg write failed(%d)\n", rc);
@@ -2329,6 +2315,15 @@
 		return rc;
 	}
 
+	/* Set current ramp */
+	rc = qpnp_led_masked_write(led, FLASH_CURRENT_RAMP(led->base),
+		FLASH_CURRENT_RAMP_MASK, FLASH_RAMP_STEP_27US);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Current ramp reg write failed(%d)\n", rc);
+		return rc;
+	}
+
 	led->flash_cfg->strobe_type = 0;
 
 	/* dump flash registers */
@@ -3360,7 +3355,6 @@
 		if (led->default_on) {
 			led->cdev.brightness = led->cdev.max_brightness;
 			__qpnp_led_work(led, led->cdev.brightness);
-			schedule_work(&led->work);
 			if (led->turn_off_delay_ms > 0)
 				qpnp_led_turn_off(led);
 		} else
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 9d606a1..65387ba 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -3118,7 +3118,7 @@
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 
 	mutex_lock(&dvbdemux->mutex);
-
+	dvbdemux->sw_filter_abort = 0;
 	demux->frontend = NULL;
 	mutex_unlock(&dvbdemux->mutex);
 	return 0;
@@ -3203,6 +3203,7 @@
 		return -ENOMEM;
 	}
 
+	dvbdemux->sw_filter_abort = 0;
 	dvbdemux->total_process_time = 0;
 	dvbdemux->total_crc_time = 0;
 	snprintf(dvbdemux->alias,
diff --git a/drivers/media/platform/msm/camera_v1/msm_v4l2_video.c b/drivers/media/platform/msm/camera_v1/msm_v4l2_video.c
index 1849bf6..23e74ef 100644
--- a/drivers/media/platform/msm/camera_v1/msm_v4l2_video.c
+++ b/drivers/media/platform/msm/camera_v1/msm_v4l2_video.c
@@ -742,6 +742,9 @@
 	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
 	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + v4l2_ram_size);
 
+	if (!start)
+		return -EINVAL;
+
 	/*
 	 * This is probably unnecessary now - the last PAGE_SHIFT
 	 * bits of start should be 0 now, since we are page aligning
@@ -749,16 +752,20 @@
 	 */
 	start &= PAGE_MASK;
 
+	if ((vma->vm_end <= vma->vm_start) ||
+	    (off >= len) ||
+	    ((vma->vm_end - vma->vm_start) > (len - off))) {
+		pr_err("v4l2 map request, memory requested out of bounds\n");
+		return -EINVAL;
+	}
+
 	pr_debug("v4l2 map req for phys(%p,%p) offset %u to virt (%p,%p)\n",
 	(void *)(start+off), (void *)(start+off+(vma->vm_end - vma->vm_start)),
 	(unsigned int)off, (void *)vma->vm_start, (void *)vma->vm_end);
 
-	if ((vma->vm_end - vma->vm_start + off) > len) {
-		pr_err("v4l2 map request, memory requested too big\n");
-		return -EINVAL;
-	}
-
 	start += off;
+	if (start < off)
+		return -EINVAL;
 	vma->vm_pgoff = start >> PAGE_SHIFT;
 	/* This is an IO map - tell maydump to skip this VMA */
 	vma->vm_flags |= VM_IO | VM_RESERVED;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 0313161..eda6150 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -539,6 +539,7 @@
 		goto vb2_q_fail;
 
 	if (!atomic_read(&pvdev->opened)) {
+		pm_stay_awake(&pvdev->vdev->dev);
 
 		/* create a new session when first opened */
 		rc = msm_create_session(pvdev->vdev->num, pvdev->vdev);
@@ -572,6 +573,7 @@
 command_ack_q_fail:
 	msm_destroy_session(pvdev->vdev->num);
 session_fail:
+	pm_relax(&pvdev->vdev->dev);
 	camera_v4l2_vb2_q_release(filep);
 vb2_q_fail:
 	camera_v4l2_fh_release(filep);
@@ -621,6 +623,7 @@
 		/* This should take care of both normal close
 		 * and application crashes */
 		msm_destroy_session(pvdev->vdev->num);
+		pm_relax(&pvdev->vdev->dev);
 		atomic_set(&pvdev->stream_cnt, 0);
 
 	} else {
@@ -723,6 +726,7 @@
 	atomic_set(&pvdev->opened, 0);
 	atomic_set(&pvdev->stream_cnt, 0);
 	video_set_drvdata(pvdev->vdev, pvdev);
+	device_init_wakeup(&pvdev->vdev->dev, 1);
 	goto init_end;
 
 video_register_fail:
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
index 769e2a8..5201134 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
@@ -232,6 +232,7 @@
 			msm_jpeg_irq_handler(
 				MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
 				context, data);
+		pgmn_dev->state = MSM_JPEG_INIT;
 	}
 	if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
 		data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h
index f970c79..4fbab4b 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -55,7 +55,7 @@
 
 #define JPEG_OFFLINE_CMD_START 0x00000001
 
-#define JPEG_RESET_DEFAULT 0x00020000
+#define JPEG_RESET_DEFAULT 0x00032013
 
 #define JPEG_IRQ_DISABLE_ALL 0x00000000
 #define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 1fd1065..efa3ad0 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -680,9 +680,14 @@
 	}
 
 	/* should wait on session based condition */
-	rc = wait_event_interruptible_timeout(cmd_ack->wait,
-		!list_empty_careful(&cmd_ack->command_q.list),
-		msecs_to_jiffies(timeout));
+	do {
+		rc = wait_event_interruptible_timeout(cmd_ack->wait,
+			!list_empty_careful(&cmd_ack->command_q.list),
+			msecs_to_jiffies(timeout));
+		if (rc != -ERESTARTSYS)
+			break;
+	} while (1);
+
 	if (list_empty_careful(&cmd_ack->command_q.list)) {
 		if (!rc) {
 			pr_err("%s: Timed out\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index 46c7d67..32b7222 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -17,7 +17,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <linux/pm_qos.h>
-#include <linux/wakelock.h>
 #include <linux/msm_ion.h>
 #include <linux/iommu.h>
 #include <media/v4l2-dev.h>
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 16a1616..bb2b074 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -79,6 +79,11 @@
 	struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl;
 	CDBG("Enter\n");
 	for (i = 0; i < size; i++) {
+		/* check that the index into i2c_tbl cannot grow larger that
+		the allocated size of i2c_tbl */
+		if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index)) {
+			break;
+		}
 		if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
 			value = (next_lens_position <<
 				write_arr[i].data_shift) |
@@ -196,11 +201,19 @@
 	struct msm_actuator_move_params_t *move_params)
 {
 	int32_t dest_step_position = move_params->dest_step_pos;
+	struct damping_params_t ringing_params_kernel;
 	int32_t rc = 0;
 	int32_t num_steps = move_params->num_steps;
 	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
+	if (copy_from_user(&ringing_params_kernel,
+		&(move_params->ringing_params[0]),
+		sizeof(struct damping_params_t))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
 	if (num_steps == 0)
 		return rc;
 
@@ -208,7 +221,7 @@
 	a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
 		(num_steps *
 		a_ctrl->region_params[0].code_per_step),
-		move_params->ringing_params[0].hw_params, 0);
+		ringing_params_kernel.hw_params, 0);
 
 	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
 	reg_setting.data_type = a_ctrl->i2c_data_type;
@@ -230,6 +243,7 @@
 	struct msm_actuator_move_params_t *move_params)
 {
 	int32_t rc = 0;
+	struct damping_params_t ringing_params_kernel;
 	int8_t sign_dir = move_params->sign_dir;
 	uint16_t step_boundary = 0;
 	uint16_t target_step_pos = 0;
@@ -240,6 +254,14 @@
 	int32_t num_steps = move_params->num_steps;
 	struct msm_camera_i2c_reg_setting reg_setting;
 
+	if (copy_from_user(&ringing_params_kernel,
+		&(move_params->ringing_params[a_ctrl->curr_region_index]),
+		sizeof(struct damping_params_t))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
+
 	CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
 
 	if (dest_step_pos == a_ctrl->curr_step_pos)
@@ -262,9 +284,7 @@
 				a_ctrl->step_position_table[target_step_pos];
 			a_ctrl->func_tbl->actuator_write_focus(a_ctrl,
 					curr_lens_pos,
-					&(move_params->
-						ringing_params[a_ctrl->
-						curr_region_index]),
+					&ringing_params_kernel,
 					sign_dir,
 					target_lens_pos);
 			curr_lens_pos = target_lens_pos;
@@ -275,8 +295,7 @@
 				a_ctrl->step_position_table[target_step_pos];
 			a_ctrl->func_tbl->actuator_write_focus(a_ctrl,
 					curr_lens_pos,
-					&(move_params->ringing_params[a_ctrl->
-						curr_region_index]),
+					&ringing_params_kernel,
 					sign_dir,
 					target_lens_pos);
 			curr_lens_pos = target_lens_pos;
@@ -437,8 +456,11 @@
 
 	a_ctrl->i2c_data_type = set_info->actuator_params.i2c_data_type;
 	a_ctrl->i2c_client.addr_type = set_info->actuator_params.i2c_addr_type;
-	a_ctrl->reg_tbl_size = set_info->actuator_params.reg_tbl_size;
-	if (a_ctrl->reg_tbl_size > MAX_ACTUATOR_REG_TBL_SIZE) {
+	if (set_info->actuator_params.reg_tbl_size <=
+		MAX_ACTUATOR_REG_TBL_SIZE) {
+		a_ctrl->reg_tbl_size = set_info->actuator_params.reg_tbl_size;
+	} else {
+		a_ctrl->reg_tbl_size = 0;
 		pr_err("MAX_ACTUATOR_REG_TBL_SIZE is exceeded.\n");
 		return -EFAULT;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 968dcd7..aacc07b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -95,7 +95,7 @@
 static void msm_cci_flush_queue(struct cci_device *cci_dev,
 	enum cci_i2c_master_t master)
 {
-	uint32_t rc = 0;
+	int32_t rc = 0;
 
 	msm_camera_io_w(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR);
 	rc = wait_for_completion_interruptible_timeout(
@@ -645,7 +645,7 @@
 static int32_t msm_cci_init(struct v4l2_subdev *sd,
 	struct msm_camera_cci_ctrl *c_ctrl)
 {
-	int rc = 0;
+	int32_t rc = 0;
 	struct cci_device *cci_dev;
 	enum cci_i2c_master_t master;
 	cci_dev = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 7f13568..45db19c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -48,10 +48,12 @@
 			e_ctrl->num_bytes;
 		break;
 	case CFG_EEPROM_READ_CAL_DATA:
-		CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
-		rc = copy_to_user(cdata->cfg.read_data.dbuffer,
+		if (cdata->cfg.read_data.num_bytes <= e_ctrl->num_bytes) {
+			CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
+			rc = copy_to_user(cdata->cfg.read_data.dbuffer,
 			e_ctrl->memory_data,
 			cdata->cfg.read_data.num_bytes);
+		}
 		break;
 	default:
 		break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 20905c9..01d2c13 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -29,6 +29,7 @@
 extern int32_t msm_led_torch_create_classdev(
 				struct platform_device *pdev, void *data);
 
+static enum flash_type flashtype;
 static struct msm_led_flash_ctrl_t fctrl;
 
 static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
@@ -119,6 +120,7 @@
 	struct device_node *of_node = pdev->dev.of_node;
 	struct device_node *flash_src_node = NULL;
 	uint32_t count = 0;
+	struct led_trigger *temp = NULL;
 
 	CDBG("called\n");
 
@@ -137,11 +139,18 @@
 	}
 	CDBG("pdev id %d\n", pdev->id);
 
+	rc = of_property_read_u32(of_node,
+			"qcom,flash-type", &flashtype);
+	if (rc < 0) {
+		pr_err("flash-type: read failed\n");
+		return -EINVAL;
+	}
+
 	if (of_get_property(of_node, "qcom,flash-source", &count)) {
 		count /= sizeof(uint32_t);
 		CDBG("count %d\n", count);
 		if (count > MAX_LED_TRIGGERS) {
-			pr_err("failed\n");
+			pr_err("invalid count\n");
 			return -EINVAL;
 		}
 		fctrl.num_sources = count;
@@ -157,7 +166,7 @@
 				"linux,default-trigger",
 				&fctrl.flash_trigger_name[i]);
 			if (rc < 0) {
-				pr_err("failed\n");
+				pr_err("default-trigger: read failed\n");
 				of_node_put(flash_src_node);
 				continue;
 			}
@@ -165,12 +174,18 @@
 			CDBG("default trigger %s\n",
 				fctrl.flash_trigger_name[i]);
 
-			rc = of_property_read_u32(flash_src_node,
-				"qcom,current", &fctrl.flash_op_current[i]);
-			if (rc < 0) {
-				pr_err("failed rc %d\n", rc);
-				of_node_put(flash_src_node);
-				continue;
+			if (flashtype == GPIO_FLASH) {
+				/* use fake current */
+				fctrl.flash_op_current[i] = LED_FULL;
+			} else {
+				rc = of_property_read_u32(flash_src_node,
+					"qcom,current",
+					&fctrl.flash_op_current[i]);
+				if (rc < 0) {
+					pr_err("current: read failed\n");
+					of_node_put(flash_src_node);
+					continue;
+				}
 			}
 
 			of_node_put(flash_src_node);
@@ -180,6 +195,10 @@
 
 			led_trigger_register_simple(fctrl.flash_trigger_name[i],
 				&fctrl.flash_trigger[i]);
+
+			if (flashtype == GPIO_FLASH)
+				if (fctrl.flash_trigger[i])
+					temp = fctrl.flash_trigger[i];
 		}
 
 		/* Torch source */
@@ -190,25 +209,39 @@
 				"linux,default-trigger",
 				&fctrl.torch_trigger_name);
 			if (rc < 0) {
-				pr_err("failed\n");
-			} else {
-				CDBG("default trigger %s\n",
-					fctrl.torch_trigger_name);
+				pr_err("default-trigger: read failed\n");
+				goto torch_failed;
+			}
 
+			CDBG("default trigger %s\n",
+				fctrl.torch_trigger_name);
+
+			if (flashtype == GPIO_FLASH) {
+				/* use fake current */
+				fctrl.torch_op_current = LED_FULL;
+				if (temp)
+					fctrl.torch_trigger = temp;
+				else
+					led_trigger_register_simple(
+						fctrl.torch_trigger_name,
+						&fctrl.torch_trigger);
+			} else {
 				rc = of_property_read_u32(flash_src_node,
 					"qcom,current",
 					&fctrl.torch_op_current);
 				if (rc < 0) {
-					pr_err("failed rc %d\n", rc);
-				} else {
-					CDBG("torch max_current %d\n",
-						fctrl.torch_op_current);
-
-					led_trigger_register_simple(
-						fctrl.torch_trigger_name,
-						&fctrl.torch_trigger);
+					pr_err("current: read failed\n");
+					goto torch_failed;
 				}
+
+				CDBG("torch max_current %d\n",
+					fctrl.torch_op_current);
+
+				led_trigger_register_simple(
+					fctrl.torch_trigger_name,
+					&fctrl.torch_trigger);
 			}
+torch_failed:
 			of_node_put(flash_src_node);
 		}
 	}
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 2bc460b..e3a539c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -2096,7 +2096,7 @@
 {
 	int left_size, copy_len;
 
-	/* Remainning header bytes that need to be processed? */
+	/* Remaining header bytes that need to be processed? */
 	if (!feed_data->pes_header_left_bytes)
 		return 0;
 
@@ -4107,7 +4107,8 @@
 	struct dmx_data_ready pes_event;
 	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
 	struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *)
-				feed->feed.ts.buffer.ringbuff;
+		feed->feed.ts.buffer.ringbuff;
+	ssize_t bytes_avail;
 
 	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
 		goto pes_filter_check_overflow;
@@ -4139,13 +4140,18 @@
 	}
 
 	while (sts->metadata_fill_count) {
-		if (dvb_ringbuffer_avail(&mpq_feed->metadata_buf) <
-			(sizeof(header) + sizeof(counters))) {
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < (sizeof(header) + sizeof(counters))) {
 			MPQ_DVB_ERR_PRINT(
-				"%s: metadata_fill_count is %d but actual buffer has less than %d bytes\n",
+				"%s: metadata_fill_count is %d less than required %d bytes\n",
 				__func__,
 				sts->metadata_fill_count,
 				sizeof(header) + sizeof(counters));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
 			break;
 		}
 
@@ -4230,6 +4236,7 @@
 	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
 	struct dvb_demux_filter *f;
 	struct dmx_section_feed *sec = &feed->feed.sec;
+	ssize_t bytes_avail;
 
 	/* Parse error indicators */
 	if (sts->error_indicators & SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL) {
@@ -4250,6 +4257,21 @@
 	mpq_feed->sdmx_buf.pwrite = sts->data_write_offset;
 
 	while (sts->metadata_fill_count) {
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < sizeof(header)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %d bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
 		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
 			sizeof(header));
 		sts->metadata_fill_count -= sizeof(header);
@@ -4288,10 +4310,10 @@
 	u8 metadata_buf[MAX_SDMX_METADATA_LENGTH];
 	struct mpq_streambuffer *sbuf;
 	int ret;
-	int pes_cnt = 0;
 	struct dmx_data_ready data_event;
 	struct dmx_data_ready data;
 	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	ssize_t bytes_avail;
 
 	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
 		goto decoder_filter_check_flags;
@@ -4318,7 +4340,21 @@
 		struct mpq_streambuffer_packet_header packet;
 		struct mpq_adapter_video_meta_data meta_data;
 
-		pes_cnt++;
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < (sizeof(header) + sizeof(counters))) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %d bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header) + sizeof(counters));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
 		/* Read metadata header */
 		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header,
 			sizeof(header));
@@ -4334,15 +4370,28 @@
 		sts->metadata_fill_count -= sizeof(counters);
 
 		/* Read metadata - TS & PES headers */
-		if (header.metadata_length < MAX_SDMX_METADATA_LENGTH)
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if ((header.metadata_length < MAX_SDMX_METADATA_LENGTH) &&
+			(header.metadata_length >= sizeof(counters)) &&
+			(bytes_avail >=
+			 (header.metadata_length - sizeof(counters)))) {
 			dvb_ringbuffer_read(&mpq_feed->metadata_buf,
 				metadata_buf,
 				header.metadata_length - sizeof(counters));
-		else
+		} else {
 			MPQ_DVB_ERR_PRINT(
-				"%s: meta-data size=%d is too big for meta-data buffer=%d\n",
+				"%s: meta-data size %d larger than available meta-data %d or max allowed %d\n",
 				__func__, header.metadata_length,
+				bytes_avail,
 				MAX_SDMX_METADATA_LENGTH);
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
 		sts->metadata_fill_count -=
 			(header.metadata_length - sizeof(counters));
 
@@ -4475,6 +4524,7 @@
 	u8 buf[TS_PACKET_HEADER_LENGTH + MAX_TSP_ADAPTATION_LENGTH +
 	       TIMESTAMP_LEN];
 	size_t stc_len = 0;
+	ssize_t bytes_avail;
 
 	if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
 		MPQ_DVB_ERR_PRINT("%s: internal PCR buffer overflowed!\n",
@@ -4490,6 +4540,21 @@
 	rbuff->pwrite = sts->data_write_offset;
 
 	while (sts->metadata_fill_count) {
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < sizeof(header)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %d bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
 		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
 			sizeof(header));
 		MPQ_DVB_DBG_PRINT(
@@ -4775,6 +4840,14 @@
 		todo = fill_count > limit ? limit : fill_count;
 		ret = mpq_sdmx_process_buffer(mpq_demux, input, todo,
 			read_offset);
+
+		if (mpq_demux->demux.sw_filter_abort) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: Demuxing from DVR was aborted\n",
+				__func__);
+			return -ENODEV;
+		}
+
 		if (ret > 0) {
 			total_bytes_read += ret;
 			fill_count -= ret;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index e982feb..30ada3e 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -275,12 +275,18 @@
 	case HAL_BUFFER_OUTPUT:
 		buffer = HFI_BUFFER_OUTPUT;
 		break;
+	case HAL_BUFFER_OUTPUT2:
+		buffer = HFI_BUFFER_OUTPUT2;
+		break;
 	case HAL_BUFFER_EXTRADATA_INPUT:
 		buffer = HFI_BUFFER_EXTRADATA_INPUT;
 		break;
 	case HAL_BUFFER_EXTRADATA_OUTPUT:
 		buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
 		break;
+	case HAL_BUFFER_EXTRADATA_OUTPUT2:
+		buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
+		break;
 	case HAL_BUFFER_INTERNAL_SCRATCH:
 		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
 		break;
@@ -1178,7 +1184,50 @@
 		break;
 	}
 	case HAL_CONFIG_VPE_OPERATIONS:
+	{
+		struct hfi_operations_type *hfi;
+		struct hal_operations *prop =
+			(struct hal_operations *) pdata;
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS;
+		hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1];
+		switch (prop->rotate) {
+		case HAL_ROTATE_NONE:
+			hfi->rotation = HFI_ROTATE_NONE;
+			break;
+		case HAL_ROTATE_90:
+			hfi->rotation = HFI_ROTATE_90;
+			break;
+		case HAL_ROTATE_180:
+			hfi->rotation = HFI_ROTATE_180;
+			break;
+		case HAL_ROTATE_270:
+			hfi->rotation = HFI_ROTATE_270;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid rotation setting: 0x%x",
+				prop->rotate);
+			rc = -EINVAL;
+			break;
+		}
+		switch (prop->flip) {
+		case HAL_FLIP_NONE:
+			hfi->flip = HFI_FLIP_NONE;
+			break;
+		case HAL_FLIP_HORIZONTAL:
+			hfi->flip = HFI_FLIP_HORIZONTAL;
+			break;
+		case HAL_FLIP_VERTICAL:
+			hfi->flip = HFI_FLIP_VERTICAL;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid flip setting: 0x%x",
+				prop->flip);
+			rc = -EINVAL;
+			break;
+		}
+		pkt->size += sizeof(u32) + sizeof(struct hfi_operations_type);
 		break;
+	}
 	case HAL_PARAM_VENC_INTRA_REFRESH:
 	{
 		struct hfi_intra_refresh *hfi;
@@ -1302,7 +1351,15 @@
 		break;
 	}
 	case HAL_CONFIG_VPE_DEINTERLACE:
+	{
+		struct hfi_enable *hfi;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VPE_DEINTERLACE;
+		hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+		hfi->enable = ((struct hal_enable *) pdata)->enable;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
 		break;
+	}
 	case HAL_PARAM_VENC_H264_GENERATE_AUDNAL:
 	{
 		struct hfi_enable *hfi;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 2bd038d..abdb039 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -957,6 +957,7 @@
 		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
 		data_done.output_done.extra_data_buffer =
 			pkt->extra_data_buffer;
+		data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
 		dprintk(VIDC_DBG, "FBD: Received buf: %p, of len: %d\n",
 				   pkt->packet_buffer, pkt->filled_len);
 	} else if (is_decoder == 1) {
@@ -1209,7 +1210,7 @@
 				version[i] = ' ';
 		}
 		version[i] = '\0';
-		dprintk(VIDC_INFO, "F/W version: %s\n", version);
+		dprintk(VIDC_DBG, "F/W version: %s\n", version);
 	}
 
 	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 4425909..dc384bc 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -31,16 +31,16 @@
 enum hal_buffer {
 	HAL_BUFFER_INPUT = 0x1,
 	HAL_BUFFER_OUTPUT = 0x2,
-	HAL_BUFFER_OUTPUT2 = 0x2,
-	HAL_BUFFER_EXTRADATA_INPUT = 0x4,
-	HAL_BUFFER_EXTRADATA_OUTPUT = 0x8,
-	HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x8,
-	HAL_BUFFER_INTERNAL_SCRATCH = 0x10,
-	HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x20,
-	HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x40,
-	HAL_BUFFER_INTERNAL_PERSIST = 0x80,
-	HAL_BUFFER_INTERNAL_PERSIST_1 = 0x100,
-	HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x200,
+	HAL_BUFFER_OUTPUT2 = 0x4,
+	HAL_BUFFER_EXTRADATA_INPUT = 0x8,
+	HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
+	HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
+	HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
+	HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
+	HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
+	HAL_BUFFER_INTERNAL_PERSIST = 0x200,
+	HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
+	HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
 };
 
 struct msm_smem {
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 81afd5c..468ba74 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -35,7 +35,7 @@
 
 struct msm_vidc_drv *vidc_driver;
 
-uint32_t msm_vidc_pwr_collapse_delay = 2000;
+uint32_t msm_vidc_pwr_collapse_delay = 10000;
 
 static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
 {
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index ea91849..f4fdfe7 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -307,6 +307,22 @@
 		.qmenu = NULL,
 		.cluster = 0,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
+		.name = "Video decoder multi stream",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+		.maximum =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
+		.default_value =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.step = 1,
+		.qmenu = NULL,
+		.cluster = 0,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -496,7 +512,8 @@
 				b->m.planes[i].length);
 			}
 			buffer_info.buffer_size = b->m.planes[0].length;
-			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+			buffer_info.buffer_type =
+				msm_comm_get_hal_output_buffer(inst);
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
 				b->m.planes[0].m.userptr;
@@ -580,7 +597,8 @@
 				b->m.planes[i].length);
 			}
 			buffer_info.buffer_size = b->m.planes[0].length;
-			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+			buffer_info.buffer_type =
+				msm_comm_get_hal_output_buffer(inst);
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
 				 b->m.planes[0].m.userptr;
@@ -668,7 +686,6 @@
 int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 {
 	const struct msm_vidc_format *fmt = NULL;
-	struct hal_frame_size frame_sz;
 	struct hfi_device *hdev;
 	int stride, scanlines;
 	int extra_idx = 0;
@@ -690,8 +707,22 @@
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		if (inst->in_reconfig == true) {
-			inst->prop.height = inst->reconfig_height;
-			inst->prop.width = inst->reconfig_width;
+			if (msm_comm_get_stream_output_mode(inst) ==
+				HAL_VIDEO_DECODER_PRIMARY) {
+				inst->prop.height[CAPTURE_PORT] =
+					inst->reconfig_height;
+				inst->prop.width[CAPTURE_PORT] =
+					inst->reconfig_width;
+				inst->prop.height[OUTPUT_PORT] =
+					inst->reconfig_height;
+				inst->prop.width[OUTPUT_PORT] =
+					inst->reconfig_width;
+			} else {
+				inst->prop.height[OUTPUT_PORT] =
+					inst->reconfig_height;
+				inst->prop.width[OUTPUT_PORT] =
+					inst->reconfig_width;
+			}
 			rc = msm_vidc_check_session_supported(inst);
 			if (rc) {
 				dprintk(VIDC_ERR,
@@ -699,15 +730,10 @@
 				goto exit;
 			}
 		}
-		f->fmt.pix_mp.height = inst->prop.height;
-		f->fmt.pix_mp.width = inst->prop.width;
-		stride = inst->prop.width;
-		scanlines = inst->prop.height;
-		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
-		frame_sz.width = inst->prop.width;
-		frame_sz.height = inst->prop.height;
-		dprintk(VIDC_DBG, "width = %d, height = %d\n",
-				frame_sz.width, frame_sz.height);
+		f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+		f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+		stride = inst->prop.width[CAPTURE_PORT];
+		scanlines = inst->prop.height[CAPTURE_PORT];
 		rc = msm_comm_try_get_bufreqs(inst);
 		if (rc) {
 			dprintk(VIDC_ERR,
@@ -717,19 +743,15 @@
 		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 			for (i = 0; i < fmt->num_planes; ++i) {
 				f->fmt.pix_mp.plane_fmt[i].sizeimage =
-					fmt->get_frame_size(i,
-						inst->capability.height.max,
-						inst->capability.width.max);
-				inst->bufq[OUTPUT_PORT].
-					vb2_bufq.plane_sizes[i] =
-					f->fmt.pix_mp.plane_fmt[i].sizeimage;
+				inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i];
 			}
 		} else {
 			switch (fmt->fourcc) {
 			case V4L2_PIX_FMT_NV12:
 				call_hfi_op(hdev, get_stride_scanline,
 					COLOR_FMT_NV12,
-					inst->prop.width, inst->prop.height,
+					inst->prop.width[CAPTURE_PORT],
+					inst->prop.height[CAPTURE_PORT],
 					&stride, &scanlines);
 				break;
 			default:
@@ -737,7 +759,8 @@
 					"Color format not recognized\n");
 			}
 			buff_req_buffer =
-				get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+				get_buff_req_buffer(inst,
+					msm_comm_get_hal_output_buffer(inst));
 			if (buff_req_buffer)
 				f->fmt.pix_mp.plane_fmt[0].sizeimage =
 				buff_req_buffer->buffer_size;
@@ -769,9 +792,9 @@
 				(__u16)scanlines;
 		} else {
 			f->fmt.pix_mp.plane_fmt[0].bytesperline =
-				(__u16)inst->prop.width;
+				(__u16)inst->prop.width[CAPTURE_PORT];
 			f->fmt.pix_mp.plane_fmt[0].reserved[0] =
-				(__u16)inst->prop.height;
+				(__u16)inst->prop.height[CAPTURE_PORT];
 		}
 	} else {
 		dprintk(VIDC_ERR,
@@ -838,6 +861,8 @@
 	int ret = 0;
 	int i;
 	struct hal_buffer_requirements *buff_req_buffer;
+	int max_input_size = 0;
+
 	if (!inst || !f) {
 		dprintk(VIDC_ERR,
 			"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -855,7 +880,26 @@
 			rc = -EINVAL;
 			goto err_invalid_fmt;
 		}
+		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_PRIMARY) {
+			inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+			inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+		}
 		inst->fmts[fmt->type] = fmt;
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+			frame_sz.width = inst->prop.width[CAPTURE_PORT];
+			frame_sz.height = inst->prop.height[CAPTURE_PORT];
+			dprintk(VIDC_DBG,
+				"buffer type = %d width = %d, height = %d\n",
+				frame_sz.buffer_type, frame_sz.width,
+				frame_sz.height);
+			ret = msm_comm_try_set_prop(inst,
+				HAL_PARAM_FRAME_SIZE, &frame_sz);
+		}
 		ret = ret || msm_comm_try_get_bufreqs(inst);
 		if (ret) {
 			for (i = 0; i < fmt->num_planes; ++i) {
@@ -866,7 +910,8 @@
 			}
 		} else {
 			buff_req_buffer =
-				get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+				get_buff_req_buffer(inst,
+					msm_comm_get_hal_output_buffer(inst));
 			if (buff_req_buffer)
 				f->fmt.pix_mp.plane_fmt[0].sizeimage =
 				buff_req_buffer->buffer_size;
@@ -891,8 +936,13 @@
 				f->fmt.pix_mp.plane_fmt[i].sizeimage;
 		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		inst->prop.width = f->fmt.pix_mp.width;
-		inst->prop.height = f->fmt.pix_mp.height;
+		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_PRIMARY) {
+			inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+			inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		}
 		rc = msm_vidc_check_session_supported(inst);
 		if (rc) {
 			dprintk(VIDC_ERR,
@@ -917,12 +967,21 @@
 			goto err_invalid_fmt;
 		}
 		frame_sz.buffer_type = HAL_BUFFER_INPUT;
-		frame_sz.width = inst->prop.width;
-		frame_sz.height = inst->prop.height;
+		frame_sz.width = inst->prop.width[OUTPUT_PORT];
+		frame_sz.height = inst->prop.height[OUTPUT_PORT];
+		dprintk(VIDC_DBG,
+			"buffer type = %d width = %d, height = %d\n",
+			frame_sz.buffer_type, frame_sz.width,
+			frame_sz.height);
 		msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
-		f->fmt.pix_mp.plane_fmt[0].sizeimage =
-			fmt->get_frame_size(0, inst->capability.height.max,
+
+		max_input_size = fmt->get_frame_size(0,
+					inst->capability.height.max,
 					inst->capability.width.max);
+
+		if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size)
+			f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
 			inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
@@ -1046,7 +1105,8 @@
 			break;
 		}
 		mutex_lock(&inst->lock);
-		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+		bufreq = get_buff_req_buffer(inst,
+			msm_comm_get_hal_output_buffer(inst));
 		if (!bufreq) {
 			dprintk(VIDC_ERR,
 				"No buffer requirement for buffer type %x\n",
@@ -1058,7 +1118,8 @@
 		*num_buffers = max(*num_buffers, bufreq->buffer_count_min);
 		if (*num_buffers != bufreq->buffer_count_actual) {
 			property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
-			new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+			new_buf_count.buffer_type =
+				msm_comm_get_hal_output_buffer(inst);
 			new_buf_count.buffer_count_actual = *num_buffers;
 			rc = call_hfi_op(hdev, session_set_property,
 				inst->session, property_id, &new_buf_count);
@@ -1088,12 +1149,80 @@
 	return rc;
 }
 
+static int msm_vdec_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	struct hfi_device *hdev;
+	struct msm_smem *handle;
+	struct vidc_frame_data frame_data = {0};
+	struct hal_buffer_requirements *output_buf, *extradata_buf;
+	int rc = 0;
+	hdev = inst->core->device;
+
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+	if (!extradata_buf) {
+		dprintk(VIDC_DBG,
+			"This extradata buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_EXTRADATA_OUTPUT);
+		return 0;
+	}
+
+	hdev = inst->core->device;
+
+	mutex_lock(&inst->lock);
+	if (!list_empty(&inst->outputbufs)) {
+		list_for_each_entry(binfo, &inst->outputbufs, list) {
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Invalid parameter\n");
+				mutex_unlock(&inst->lock);
+				return -EINVAL;
+			}
+			handle = binfo->handle;
+			frame_data.alloc_len = output_buf->buffer_size;
+			frame_data.filled_len = 0;
+			frame_data.offset = 0;
+			frame_data.device_addr = handle->device_addr;
+			frame_data.flags = 0;
+			frame_data.extradata_addr = handle->device_addr +
+				output_buf->buffer_size;
+			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+			rc = call_hfi_op(hdev, session_ftb,
+					(void *) inst->session, &frame_data);
+			binfo->buffer_ownership = FIRMWARE;
+		}
+	}
+	mutex_unlock(&inst->lock);
+	return 0;
+}
+
 static inline int start_streaming(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
 	struct vb2_buf_entry *temp;
+	struct hfi_device *hdev;
 	struct list_head *ptr, *next;
+
+	hdev = inst->core->device;
 	inst->in_reconfig = false;
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY)
+		rc = msm_comm_check_scaling_supported(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "H/w scaling is not in valid range");
+		return -EINVAL;
+	}
 	rc = msm_comm_set_scratch_buffers(inst);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -1107,6 +1236,15 @@
 		goto fail_start;
 	}
 
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_comm_set_output_buffers(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set output buffers: %d\n", rc);
+			goto fail_start;
+		}
+	}
 	mutex_lock(&inst->core->sync_lock);
 	msm_comm_scale_clocks_and_bus(inst);
 	mutex_unlock(&inst->core->sync_lock);
@@ -1117,7 +1255,15 @@
 			"Failed to move inst: %p to start done state\n", inst);
 		goto fail_start;
 	}
-
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_vdec_queue_output_buffers(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to queue output buffers: %d\n", rc);
+			goto fail_start;
+		}
+	}
 	mutex_lock(&inst->sync_lock);
 	if (!list_empty(&inst->pendingq)) {
 		list_for_each_safe(ptr, next, &inst->pendingq) {
@@ -1311,8 +1457,10 @@
 	}
 	inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
 	inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
-	inst->prop.height = DEFAULT_HEIGHT;
-	inst->prop.width = DEFAULT_WIDTH;
+	inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+	inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
 	inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
 	inst->capability.height.max = DEFAULT_HEIGHT;
 	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
@@ -1371,6 +1519,7 @@
 	struct hfi_device *hdev;
 	struct hal_extradata_enable extra;
 	struct hal_buffer_alloc_mode alloc_mode;
+	struct hal_multi_stream multi_stream;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1498,7 +1647,70 @@
 		pdata = &alloc_mode;
 		inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
 		break;
-
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+		if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+				HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Downscaling not supported: 0x%x",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+			multi_stream.enable = true;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed : Enabling OUTPUT port : %d\n",
+					rc);
+				break;
+			}
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+			multi_stream.enable = false;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed:Disabling OUTPUT2 port : %d\n",
+					rc);
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+			multi_stream.enable = true;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed :Enabling OUTPUT2 port : %d\n",
+					rc);
+				break;
+			}
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+			multi_stream.enable = false;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed :Disabling OUTPUT port : %d\n",
+					rc);
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Failed : Unsupported multi stream setting\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
 	default:
 		break;
 	}
@@ -1519,6 +1731,10 @@
 	int rc = 0, c = 0;
 	struct msm_vidc_inst *inst = container_of(ctrl->handler,
 				struct msm_vidc_inst, ctrl_handler);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return -EINVAL;
+	}
 	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 	if (rc) {
 		dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 9e8a639..f9b5519 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -25,9 +25,9 @@
 #define MAX_BIT_RATE 160000000
 #define DEFAULT_BIT_RATE 64000
 #define BIT_RATE_STEP 100
-#define MIN_FRAME_RATE 65536
-#define MAX_FRAME_RATE 15728640
-#define DEFAULT_FRAME_RATE 1966080
+#define MIN_FRAME_RATE 1
+#define MAX_FRAME_RATE 240
+#define DEFAULT_FRAME_RATE 15
 #define DEFAULT_IR_MBS 30
 #define MAX_SLICE_BYTE_SIZE 1024
 #define MIN_SLICE_BYTE_SIZE 1024
@@ -134,7 +134,8 @@
 	MSM_VENC_CTRL_CLUSTER_BITRATE = 1 << 8,
 	MSM_VENC_CTRL_CLUSTER_TIMING = 1 << 9,
 	MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL = 1 << 10,
-	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 11,
+	MSM_VENC_CTRL_CLUSTER_DEINTERLACE = 1 << 11,
+	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 12,
 };
 
 static struct msm_vidc_ctrl msm_venc_ctrls[] = {
@@ -400,7 +401,7 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
 		),
 		.qmenu = mpeg_video_rotation,
-		.cluster = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_DEINTERLACE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
@@ -718,6 +719,16 @@
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
 		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE,
+		.name = "Deinterlace for encoder",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+		.step = 1,
+		.cluster = MSM_VENC_CTRL_CLUSTER_DEINTERLACE,
 	}
 };
 
@@ -844,7 +855,8 @@
 		inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
 		for (i = 0; i < *num_planes; i++) {
 			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
-					i, inst->prop.height, inst->prop.width);
+					i, inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
 		}
 		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
 		new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
@@ -881,7 +893,8 @@
 				inst->buff_req.buffer[0].buffer_count_actual);
 		for (i = 0; i < *num_planes; i++) {
 			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
-					i, inst->prop.height, inst->prop.width);
+					i, inst->prop.height[OUTPUT_PORT],
+					inst->prop.width[OUTPUT_PORT]);
 		}
 		break;
 	default:
@@ -897,7 +910,13 @@
 	int rc = 0;
 	struct vb2_buf_entry *temp;
 	struct list_head *ptr, *next;
-
+	if (inst->capability.pixelprocess_capabilities &
+		HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
+		rc = msm_comm_check_scaling_supported(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "H/w scaling is not in valid range");
+		return -EINVAL;
+	}
 	rc = msm_comm_try_get_bufreqs(inst);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -1212,6 +1231,19 @@
 		default:
 			goto unknown_value;
 		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
+			return HAL_ROTATE_NONE;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90:
+			return HAL_ROTATE_90;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180:
+			return HAL_ROTATE_180;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270:
+			return HAL_ROTATE_270;
+		default:
+			goto unknown_value;
+		}
 	}
 
 unknown_value:
@@ -1257,8 +1289,9 @@
 		if (!__temp) { \
 			dprintk(VIDC_ERR, "Can't find %s (%x) in cluster", \
 				#__ctrl_id, __ctrl_id); \
-			rc = -ENOENT; \
-			break; \
+			/* Clusters are hardcoded, if we can't find */ \
+			/* something then things are massively screwed up */ \
+			BUG_ON(1); \
 		} \
 		__temp; \
 	})
@@ -1270,11 +1303,15 @@
 		idr_period.idr_period = ctrl->val;
 		pdata = &idr_period;
 		break;
-	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: {
-		struct v4l2_ctrl *b;
-		b = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+	{
+		int num_p, num_b;
+		struct v4l2_ctrl update_ctrl = {.id = 0, .val = 0};
 
-		if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
+		if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_PERIOD &&
+			inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
 			inst->fmts[CAPTURE_PORT]->fourcc !=
 				V4L2_PIX_FMT_H264_NO_SC) {
 			dprintk(VIDC_ERR, "Control 0x%x only valid for H264",
@@ -1283,110 +1320,115 @@
 			break;
 		}
 
-		/*
-		 * We can't set the I-period explicitly. So set it implicitly
-		 * by setting the number of P and B frames per I-period
-		 */
-		property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
-		intra_period.pframes = (ctrl->val - 1) - b->val;
-		intra_period.bframes = b->val;
-		pdata = &intra_period;
-		break;
-	}
-	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
-		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
 
-		property_id =
-			HAL_CONFIG_VENC_INTRA_PERIOD;
-		intra_period.pframes = ctrl->val;
-		intra_period.bframes = temp_ctrl->val;
-		pdata = &intra_period;
-		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+		num_b = temp_ctrl->val;
+
 		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
-		intra_period.bframes = ctrl->val;
-		intra_period.pframes = temp_ctrl->val;
-		if (intra_period.bframes) {
+		num_p = temp_ctrl->val;
+
+		/* V4L2_CID_MPEG_VIDEO_H264_I_PERIOD and _NUM_P_FRAMES are
+		 * implicitly tied to each other.  If either is adjusted,
+		 * the other needs to be adjusted in a complementary manner.
+		 * Ideally we adjust _NUM_B_FRAMES as well but we'll leave it
+		 * alone for now */
+		if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_PERIOD) {
+			num_p = ctrl->val - 1 - num_b;
+			update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES;
+			update_ctrl.val = num_p;
+		} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES) {
+			num_p = ctrl->val;
+			update_ctrl.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+			update_ctrl.val = num_p + num_b;
+		} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) {
+			num_b = ctrl->val;
+			update_ctrl.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
+			update_ctrl.val = num_p + num_b;
+		}
+
+		if (update_ctrl.id) {
+			temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
+			temp_ctrl->val = update_ctrl.val;
+		}
+
+		if (num_b) {
 			u32 max_num_b_frames = MAX_NUM_B_FRAMES;
-			property_id =
-				HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
+			property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
 			pdata = &max_num_b_frames;
 			rc = call_hfi_op(hdev, session_set_property,
 				(void *)inst->session, property_id, pdata);
 			if (rc) {
 				dprintk(VIDC_ERR,
-					"Failed : Setprop MAX_NUM_B_FRAMES"
-					"%d", rc);
+					"Failed : Setprop MAX_NUM_B_FRAMES %d",
+					rc);
 				break;
 			}
 		}
-		property_id =
-			HAL_CONFIG_VENC_INTRA_PERIOD;
+
+		property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
+		intra_period.pframes = num_p;
+		intra_period.bframes = num_b;
 		pdata = &intra_period;
+
 		break;
+	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
 		property_id =
 			HAL_CONFIG_VENC_REQUEST_IFRAME;
 		request_iframe.enable = true;
 		pdata = &request_iframe;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
 	{
-		bool cfr = true, cbr = true;
 		int final_mode = 0;
+		struct v4l2_ctrl update_ctrl = {.id = 0, .val = 0};
 
-		temp_ctrl = TRY_GET_CTRL(
-			V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
-
-		switch (temp_ctrl->val) {
-		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
-			/* Let's assume CFR */
-		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
-		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
-			cfr = true;
-			break;
-		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
-		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
-			cfr = false;
-			break;
-		default:
-			dprintk(VIDC_WARN, "Unknown framerate mode");
-		}
-
-		switch (ctrl->val) {
-		case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
-			cbr = false;
-			break;
-		case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
-			cbr = true;
-			break;
-		default:
-			dprintk(VIDC_WARN, "Unknown bitrate mode");
-		}
-
-		if (!cfr && !cbr)
-			final_mode =
-				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
-		else if (!cfr && cbr)
-			final_mode =
-				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR;
-		else if (cfr && !cbr)
-			final_mode =
+		/* V4L2_CID_MPEG_VIDEO_BITRATE_MODE and _RATE_CONTROL
+		 * manipulate the same thing.  If one control's state
+		 * changes, try to mirror the state in the other control's
+		 * value */
+		if (ctrl->id == V4L2_CID_MPEG_VIDEO_BITRATE_MODE) {
+			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+				final_mode = HAL_RATE_CONTROL_VBR_CFR;
+				update_ctrl.val =
 				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
-		else /* ... if (cfr && cbr) */
-			final_mode =
+			} else {/* ...if (ctrl->val == _BITRATE_MODE_CBR) */
+				final_mode = HAL_RATE_CONTROL_CBR_CFR;
+				update_ctrl.val =
 				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
+			}
+
+			update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
+
+		} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL) {
+			switch (ctrl->val) {
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+				update_ctrl.val =
+					V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+				update_ctrl.val =
+					V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+			}
+
+			final_mode = ctrl->val;
+			update_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
+		}
+
+		if (update_ctrl.id) {
+			temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
+			temp_ctrl->val = update_ctrl.val;
+		}
 
 		property_id = HAL_PARAM_VENC_RATE_CONTROL;
 		property_val = final_mode;
 		pdata = &property_val;
+
 		break;
 	}
-	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
-		property_id = HAL_PARAM_VENC_RATE_CONTROL;
-		property_val = ctrl->val;
-		pdata = &property_val;
-		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE:
 		property_id =
 			HAL_CONFIG_VENC_TARGET_BITRATE;
@@ -1528,11 +1570,33 @@
 		pdata = &profile_level;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+	{
+		struct v4l2_ctrl *deinterlace = NULL;
+		if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+			HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Rotation not supported: 0x%x",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		deinterlace =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE);
+		if (ctrl->val && deinterlace && deinterlace->val !=
+				V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED) {
+			dprintk(VIDC_ERR,
+				"Rotation not supported with deinterlacing");
+			rc = -EINVAL;
+			break;
+		}
 		property_id =
 			HAL_CONFIG_VPE_OPERATIONS;
-		operations.rotate = ctrl->val;
+		operations.rotate = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+				ctrl->val);
+		operations.flip = HAL_FLIP_NONE;
 		pdata = &operations;
 		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: {
 		struct v4l2_ctrl *qpp, *qpb;
 
@@ -1875,6 +1939,37 @@
 		}
 
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE:
+	{
+		struct v4l2_ctrl *rotation = NULL;
+		if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+			HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Deinterlace not supported: 0x%x",
+					ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		rotation = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+		if (ctrl->val && rotation && rotation->val !=
+			V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) {
+			dprintk(VIDC_ERR,
+				"Deinterlacing not supported with rotation");
+			rc = -EINVAL;
+			break;
+		}
+		property_id = HAL_CONFIG_VPE_DEINTERLACE;
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED:
+			enable.enable = 1;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED:
+		default:
+			enable.enable = 0;
+			break;
+		}
+		pdata = &enable;
+		break;
+	}
 	default:
 		rc = -ENOTSUPP;
 		break;
@@ -1896,8 +1991,15 @@
 {
 
 	int rc = 0, c = 0;
+
 	struct msm_vidc_inst *inst = container_of(ctrl->handler,
 					struct msm_vidc_inst, ctrl_handler);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return -EINVAL;
+	}
+
 	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 
 	if (rc) {
@@ -1950,11 +2052,14 @@
 	}
 	inst->fmts[CAPTURE_PORT] = &venc_formats[1];
 	inst->fmts[OUTPUT_PORT] = &venc_formats[0];
-	inst->prop.height = DEFAULT_HEIGHT;
-	inst->prop.width = DEFAULT_WIDTH;
+	inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+	inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
 	inst->prop.fps = 15;
 	inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
 	inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->capability.pixelprocess_capabilities = 0;
 	return rc;
 }
 
@@ -2150,12 +2255,20 @@
 			rc = -EINVAL;
 			goto exit;
 		}
+		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		struct hal_uncompressed_format_select hal_fmt = {0};
 		struct hal_frame_size frame_sz;
 
-		inst->prop.width = f->fmt.pix_mp.width;
-		inst->prop.height = f->fmt.pix_mp.height;
+		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
 		rc = msm_vidc_check_session_supported(inst);
 		if (rc) {
 			dprintk(VIDC_ERR,
@@ -2163,8 +2276,8 @@
 			goto exit;
 		}
 		frame_sz.buffer_type = HAL_BUFFER_INPUT;
-		frame_sz.width = inst->prop.width;
-		frame_sz.height = inst->prop.height;
+		frame_sz.width = inst->prop.width[OUTPUT_PORT];
+		frame_sz.height = inst->prop.height[OUTPUT_PORT];
 		dprintk(VIDC_DBG, "width = %d, height = %d\n",
 				frame_sz.width, frame_sz.height);
 		rc = call_hfi_op(hdev, session_set_property, (void *)
@@ -2174,14 +2287,6 @@
 				"Failed to set framesize for Output port\n");
 			goto exit;
 		}
-		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
-		rc = call_hfi_op(hdev, session_set_property, (void *)
-			inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz);
-		if (rc) {
-			dprintk(VIDC_ERR,
-				"Failed to set hal property for framesize\n");
-			goto exit;
-		}
 		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
 			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
 			OUTPUT_PORT);
@@ -2226,11 +2331,23 @@
 		}
 		inst->fmts[fmt->type] = fmt;
 		if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			struct hal_frame_size frame_sz;
 			rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 			if (rc) {
 				dprintk(VIDC_ERR, "Failed to open instance\n");
 				goto exit;
 			}
+			frame_sz.width = inst->prop.width[CAPTURE_PORT];
+			frame_sz.height = inst->prop.height[CAPTURE_PORT];
+			frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+			rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, HAL_PARAM_FRAME_SIZE,
+				&frame_sz);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to set OUTPUT framesize\n");
+				goto exit;
+			}
 		}
 	} else {
 		dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
@@ -2246,32 +2363,41 @@
 	const struct msm_vidc_format *fmt = NULL;
 	int rc = 0;
 	int i;
+	u32 height, width;
 	int extra_idx = 0;
+	struct hal_buffer_requirements *buff_req_buffer;
 	if (!inst || !f) {
 		dprintk(VIDC_ERR,
 			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
-	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		fmt = inst->fmts[CAPTURE_PORT];
-	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		height = inst->prop.height[CAPTURE_PORT];
+		width = inst->prop.width[CAPTURE_PORT];
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		fmt = inst->fmts[OUTPUT_PORT];
+		height = inst->prop.height[OUTPUT_PORT];
+		width = inst->prop.width[OUTPUT_PORT];
+	}
 
 	if (fmt) {
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
-		f->fmt.pix_mp.height = inst->prop.height;
-		f->fmt.pix_mp.width = inst->prop.width;
+		f->fmt.pix_mp.height = height;
+		f->fmt.pix_mp.width = width;
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
 			f->fmt.pix_mp.plane_fmt[i].sizeimage =
-			fmt->get_frame_size(i, inst->prop.height,
-					inst->prop.width);
+			fmt->get_frame_size(i, height, width);
 		}
 		extra_idx = EXTRADATA_IDX(fmt->num_planes);
 		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			buff_req_buffer =
+				get_buff_req_buffer(inst,
+					HAL_BUFFER_EXTRADATA_OUTPUT);
 			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
-				inst->buff_req.buffer
-				[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+				buff_req_buffer ?
+				buff_req_buffer->buffer_size : 0;
 		}
 		for (i = 0; i < fmt->num_planes; ++i) {
 			inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 89fbc2a..6ed94e4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -451,12 +451,12 @@
 			!b->m.planes[i].length) {
 			continue;
 		}
+		mutex_lock(&inst->sync_lock);
 		temp = get_registered_buf(inst, b, i, &plane);
 		if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
 			dprintk(VIDC_DBG,
 				"This memory region has already been prepared\n");
 			rc = -EINVAL;
-			goto exit;
 		}
 
 		if (temp && is_dynamic_output_buffer_mode(b, inst) &&
@@ -471,12 +471,14 @@
 			*/
 			dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
 			rc = buf_ref_get(inst, temp);
-			if (rc < 0)
-				return rc;
-			save_v4l2_buffer(b, temp);
-			rc = -EEXIST;
-			goto exit;
+			if (rc > 0) {
+				save_v4l2_buffer(b, temp);
+				rc = -EEXIST;
+			}
 		}
+		mutex_unlock(&inst->sync_lock);
+		if (rc < 0)
+			goto exit;
 
 		temp = get_same_fd_buffer(inst, &inst->registered_bufs,
 					b->m.planes[i].reserved[0], &plane);
@@ -1096,6 +1098,7 @@
 	INIT_LIST_HEAD(&inst->persistbufs);
 	INIT_LIST_HEAD(&inst->ctrl_clusters);
 	INIT_LIST_HEAD(&inst->registered_bufs);
+	INIT_LIST_HEAD(&inst->outputbufs);
 	init_waitqueue_head(&inst->kernel_event_queue);
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
@@ -1202,6 +1205,17 @@
 				mutex_lock(&inst->lock);
 			}
 		}
+		if (!list_empty(&inst->outputbufs)) {
+			list_for_each_safe(ptr, next, &inst->outputbufs) {
+				buf = list_entry(ptr, struct internal_buf,
+						list);
+				list_del(&buf->list);
+				mutex_unlock(&inst->lock);
+				msm_smem_free(inst->mem_client, buf->handle);
+				kfree(buf);
+				mutex_lock(&inst->lock);
+			}
+		}
 		if (inst->extradata_handle) {
 			mutex_unlock(&inst->lock);
 			msm_smem_free(inst->mem_client, inst->extradata_handle);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 780f2c4..42460fa 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -82,6 +82,30 @@
 	}
 	return false;
 }
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
+{
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		int rc = 0;
+		struct v4l2_control ctrl = {
+			.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE
+		};
+		rc = v4l2_g_ctrl(&inst->ctrl_handler, &ctrl);
+		if (!rc && ctrl.value)
+			return HAL_VIDEO_DECODER_SECONDARY;
+	}
+	return HAL_VIDEO_DECODER_PRIMARY;
+
+
+}
+static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
+{
+	int height, width;
+	height = max(inst->prop.height[CAPTURE_PORT],
+		inst->prop.height[OUTPUT_PORT]);
+	width = max(inst->prop.width[CAPTURE_PORT],
+		inst->prop.width[OUTPUT_PORT]);
+	return NUM_MBS_PER_SEC(height, width, inst->prop.fps);
+}
 
 static int msm_comm_get_load(struct msm_vidc_core *core,
 	enum session_type type)
@@ -98,9 +122,8 @@
 			inst->state >= MSM_VIDC_OPEN_DONE &&
 			inst->state < MSM_VIDC_STOP_DONE) {
 			if (!is_thumbnail_session(inst))
-				num_mbs_per_sec += NUM_MBS_PER_SEC(
-					inst->prop.height,
-					inst->prop.width, inst->prop.fps);
+				num_mbs_per_sec +=
+					msm_comm_get_mbs_per_sec(inst);
 		}
 		mutex_unlock(&inst->lock);
 	}
@@ -416,21 +439,29 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst = NULL;
+	struct hfi_device *hdev;
+
 	if (response) {
 		struct vidc_hal_session_init_done *session_init_done =
 			(struct vidc_hal_session_init_done *)
 			response->data;
 		inst = (struct msm_vidc_inst *)response->session_id;
-		if (!inst) {
-			dprintk(VIDC_ERR, "%s: invalid input parameters",
-				__func__);
+		if (!inst || !inst->core || !inst->core->device) {
+			dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 			return;
 		}
+
+		hdev = inst->core->device;
+
 		if (!response->status && session_init_done) {
 			inst->capability.width = session_init_done->width;
 			inst->capability.height = session_init_done->height;
 			inst->capability.frame_rate =
 				session_init_done->frame_rate;
+			inst->capability.scale_x = session_init_done->scale_x;
+			inst->capability.scale_y = session_init_done->scale_y;
+			inst->capability.pixelprocess_capabilities =
+				call_hfi_op(hdev, get_core_capabilities);
 			inst->capability.capability_set = true;
 			inst->capability.buffer_mode[CAPTURE_PORT] =
 				session_init_done->alloc_mode_out;
@@ -510,6 +541,7 @@
 					"RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
 					ptr[0], ptr[1]);
 
+				mutex_lock(&inst->sync_lock);
 				/* Decrement buffer reference count*/
 				buf_ref_put(inst, binfo);
 
@@ -520,6 +552,7 @@
 				if (unmap_and_deregister_buf(inst, binfo))
 					dprintk(VIDC_ERR,
 					"%s: buffer unmap failed\n", __func__);
+				mutex_unlock(&inst->sync_lock);
 
 				/*send event to client*/
 				v4l2_event_queue_fh(&inst->event_handler,
@@ -539,8 +572,15 @@
 		} else {
 			dprintk(VIDC_DBG,
 				"V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
-			inst->prop.height = event_notify->height;
-			inst->prop.width = event_notify->width;
+			inst->prop.height[CAPTURE_PORT] = event_notify->height;
+			inst->prop.width[CAPTURE_PORT] = event_notify->width;
+			if (!msm_comm_get_stream_output_mode(inst) ==
+				HAL_VIDEO_DECODER_SECONDARY) {
+				inst->prop.height[OUTPUT_PORT] =
+					event_notify->height;
+				inst->prop.width[OUTPUT_PORT] =
+					event_notify->width;
+			}
 		}
 		rc = msm_vidc_check_session_supported(inst);
 		if (!rc) {
@@ -638,13 +678,51 @@
 			"Failed to get valid response for release resource\n");
 	}
 }
+void validate_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	u32 buffers_owned_by_driver = 0;
+	struct hal_buffer_requirements *output_buf;
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return;
+	}
+	list_for_each_entry(binfo, &inst->outputbufs, list) {
+		if (!binfo) {
+			dprintk(VIDC_ERR, "Invalid parameter\n");
+			return;
+		}
+		if (binfo->buffer_ownership != DRIVER) {
+			dprintk(VIDC_ERR,
+					"Failed : This buffer is with FW 0x%lx\n",
+					binfo->handle->device_addr);
+			return;
+		}
+		buffers_owned_by_driver++;
+	}
+	if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+		dprintk(VIDC_ERR,
+			"OUTPUT Buffer count mismatch %d of %d",
+			buffers_owned_by_driver,
+			output_buf->buffer_count_actual);
 
+	return;
+}
 static void handle_session_flush(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			mutex_lock(&inst->lock);
+			validate_output_buffers(inst);
+			mutex_unlock(&inst->lock);
+		}
 		msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
 	} else {
 		dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
@@ -878,7 +956,7 @@
 	atomic_inc(&binfo->ref_count);
 	cnt = atomic_read(&binfo->ref_count);
 	if (cnt > 2) {
-		dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
 		cnt = -EINVAL;
 	}
 	dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
@@ -905,7 +983,7 @@
 	else if (cnt == 1)
 		qbuf_again = true;
 	else {
-		dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
 		cnt = -EINVAL;
 	}
 	mutex_unlock(&inst->lock);
@@ -957,23 +1035,66 @@
 		}
 		if (flags & HAL_BUFFERFLAG_READONLY) {
 			dprintk(VIDC_DBG,
-				"_F_B_D_ fd[0] = %d -> Reference with f/w",
-				binfo->fd[0]);
+				"_F_B_D_ fd[0] = %d -> Reference with f/w, addr: 0x%x",
+				binfo->fd[0], device_addr);
 		} else {
 			dprintk(VIDC_DBG,
-				"_F_B_D_ fd[0] = %d -> FBD_ref_released\n",
-				binfo->fd[0]);
+				"_F_B_D_ fd[0] = %d -> FBD_ref_released, addr: 0x%x\n",
+				binfo->fd[0], device_addr);
 			buf_ref_put(inst, binfo);
 		}
 	}
 }
 
+static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
+	u32 dev_addr)
+{
+	struct internal_buf *binfo;
+	struct msm_smem *handle;
+	bool found = false;
+	mutex_lock(&inst->lock);
+	list_for_each_entry(binfo, &inst->outputbufs, list) {
+		if (!binfo) {
+			dprintk(VIDC_ERR, "Invalid parameter\n");
+			break;
+		}
+		handle = binfo->handle;
+		if (handle && dev_addr == handle->device_addr) {
+			if (binfo->buffer_ownership == DRIVER) {
+				dprintk(VIDC_ERR,
+					"FW returned same buffer : 0x%x\n",
+					dev_addr);
+				break;
+			}
+				binfo->buffer_ownership = DRIVER;
+			found = true;
+			break;
+		}
+	}
+	if (!found)
+		dprintk(VIDC_ERR,
+			"Failed to find output buffer in queued list: 0x%x\n",
+			dev_addr);
+	mutex_unlock(&inst->lock);
+	return 0;
+}
+
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst)
+{
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY)
+		return HAL_BUFFER_OUTPUT2;
+	else
+		return HAL_BUFFER_OUTPUT;
+}
+
 static void handle_fbd(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_data_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct vb2_buffer *vb;
+	struct vb2_buffer *vb = NULL;
 	struct vidc_hal_fbd *fill_buf_done;
+	enum hal_buffer buffer_type;
 
 	if (!response) {
 		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -981,8 +1102,18 @@
 	}
 	inst = (struct msm_vidc_inst *)response->session_id;
 	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
-	vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
-		(u32)fill_buf_done->packet_buffer1);
+	buffer_type = msm_comm_get_hal_output_buffer(inst);
+	if (fill_buf_done->buffer_type == buffer_type)
+		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+			(u32)fill_buf_done->packet_buffer1);
+	else {
+		if (handle_multi_stream_buffers(inst,
+			(u32)fill_buf_done->packet_buffer1))
+			dprintk(VIDC_ERR,
+				"Failed : Output buffer not found 0x%x\n",
+				(u32)fill_buf_done->packet_buffer1);
+		return;
+	}
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
 		vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
@@ -1571,8 +1702,8 @@
 				temp->state < MSM_VIDC_STOP_DONE) {
 			dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d\n",
 					temp->session_type,
-					temp->prop.width,
-					temp->prop.height,
+					temp->prop.width[CAPTURE_PORT],
+					temp->prop.height[CAPTURE_PORT],
 					temp->prop.fps);
 		}
 		mutex_unlock(&temp->lock);
@@ -1586,6 +1717,7 @@
 	u32 ocmem_sz = 0;
 	struct hfi_device *hdev;
 	int num_mbs_per_sec = 0;
+	int height, width;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1619,8 +1751,12 @@
 		goto exit;
 	}
 	if (inst->core->resources.has_ocmem) {
-		ocmem_sz = get_ocmem_requirement(inst->prop.height,
-						inst->prop.width);
+		height = max(inst->prop.height[CAPTURE_PORT],
+			inst->prop.height[OUTPUT_PORT]);
+		width = max(inst->prop.width[CAPTURE_PORT],
+			inst->prop.width[OUTPUT_PORT]);
+		ocmem_sz = get_ocmem_requirement(
+			height, width);
 		mutex_lock(&inst->core->sync_lock);
 		rc = msm_comm_scale_bus(inst->core, inst->session_type,
 					OCMEM_MEM);
@@ -1813,6 +1949,110 @@
 	return NULL;
 }
 
+static int set_output_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	u32 smem_flags = 0, buffer_size;
+	struct hal_buffer_requirements *output_buf, *extradata_buf;
+	int i;
+	struct hfi_device *hdev;
+
+	hdev = inst->core->device;
+
+	output_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+	if (!extradata_buf) {
+		dprintk(VIDC_DBG,
+			"This extradata buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"extradata: num = %d, size = %d\n",
+		extradata_buf->buffer_count_actual,
+		extradata_buf->buffer_size);
+
+	buffer_size = output_buf->buffer_size + extradata_buf->buffer_size;
+	if (inst->flags & VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	if (output_buf->buffer_size) {
+		for (i = 0; i < output_buf->buffer_count_actual;
+				i++) {
+			handle = msm_smem_alloc(inst->mem_client,
+					buffer_size, 1, smem_flags,
+					buffer_type, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate output memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			mutex_lock(&inst->lock);
+			binfo->handle = handle;
+			buffer_info.buffer_size = output_buf->buffer_size;
+			buffer_info.buffer_type = buffer_type;
+			binfo->buffer_type = buffer_type;
+			buffer_info.num_buffers = 1;
+			binfo->buffer_ownership = DRIVER;
+			buffer_info.align_device_addr = handle->device_addr;
+			buffer_info.extradata_addr = handle->device_addr +
+				output_buf->buffer_size;
+			buffer_info.extradata_size = extradata_buf->buffer_size;
+			dprintk(VIDC_DBG, "Output buffer address: %x",
+					buffer_info.align_device_addr);
+			dprintk(VIDC_DBG, "Output extradata address: %x",
+					buffer_info.extradata_addr);
+			rc = call_hfi_op(hdev, session_set_buffers,
+					(void *) inst->session, &buffer_info);
+			mutex_unlock(&inst->lock);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s : session_set_buffers failed",
+					__func__);
+				goto fail_set_buffers;
+			}
+			mutex_lock(&inst->lock);
+			list_add_tail(&binfo->list, &inst->outputbufs);
+			mutex_unlock(&inst->lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+	return rc;
+}
+
 static int set_scratch_buffers(struct msm_vidc_inst *inst,
 	enum hal_buffer buffer_type)
 {
@@ -2203,7 +2443,8 @@
 			frame_data.filled_len = 0;
 			frame_data.offset = 0;
 			frame_data.alloc_len = vb->v4l2_planes[0].length;
-			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+			frame_data.buffer_type =
+				msm_comm_get_hal_output_buffer(inst);
 			extra_idx =
 			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
 			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
@@ -2297,6 +2538,62 @@
 	mutex_unlock(&inst->sync_lock);
 	return rc;
 }
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct list_head *ptr, *next;
+	struct internal_buf *buf;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %p\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %p\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->lock);
+	if (!list_empty(&inst->outputbufs)) {
+		list_for_each_safe(ptr, next, &inst->outputbufs) {
+			buf = list_entry(ptr, struct internal_buf,
+					list);
+			handle = buf->handle;
+			buffer_info.buffer_size = handle->size;
+			buffer_info.buffer_type = buf->buffer_type;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			if (inst->state != MSM_VIDC_CORE_INVALID &&
+					core->state != VIDC_CORE_INVALID) {
+				buffer_info.response_required = false;
+				rc = call_hfi_op(hdev, session_release_buffers,
+					(void *)inst->session, &buffer_info);
+				if (rc)
+					dprintk(VIDC_WARN,
+						"Rel output buf fail:0x%x, %d",
+						buffer_info.align_device_addr,
+						buffer_info.buffer_size);
+			}
+			list_del(&buf->list);
+			mutex_unlock(&inst->lock);
+			msm_smem_free(inst->mem_client, buf->handle);
+			kfree(buf);
+			mutex_lock(&inst->lock);
+		}
+	}
+	mutex_unlock(&inst->lock);
+	return rc;
+}
 
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
 {
@@ -2471,6 +2768,26 @@
 	return rc;
 }
 
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_comm_release_output_buffers(inst))
+		dprintk(VIDC_WARN, "Failed to release output buffers\n");
+
+	rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
+	if (rc)
+		goto error;
+	return rc;
+error:
+	msm_comm_release_output_buffers(inst);
+	return rc;
+}
+
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
@@ -2616,6 +2933,9 @@
 				dprintk(VIDC_DBG,
 					"released buffer held in driver before issuing flush: 0x%x fd[0]: %d\n",
 					binfo->device_addr[0], binfo->fd[0]);
+				/*delete this buffer info from registered list*/
+				list_del(&binfo->list);
+				kfree(binfo);
 				/*send event to client*/
 				v4l2_event_queue_fh(&inst->event_handler,
 					&buf_event);
@@ -2670,6 +2990,7 @@
 	}
 
 	mutex_lock(&inst->sync_lock);
+	msm_comm_flush_dynamic_buffers(inst);
 	if (inst->in_reconfig && !ip_flush && op_flush) {
 		if (!list_empty(&inst->pendingq)) {
 			/*Execution can never reach here since port reconfig
@@ -2681,6 +3002,11 @@
 		}
 		rc = call_hfi_op(hdev, session_flush, inst->session,
 				HAL_FLUSH_OUTPUT);
+		if (!rc && (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY))
+			rc = call_hfi_op(hdev, session_flush, inst->session,
+				HAL_FLUSH_OUTPUT2);
+
 	} else {
 		if (!list_empty(&inst->pendingq)) {
 			/*If flush is called after queueing buffers but before
@@ -2702,8 +3028,6 @@
 			}
 		}
 
-		msm_comm_flush_dynamic_buffers(inst);
-
 		/*Do not send flush in case of session_error */
 		if (!(inst->state == MSM_VIDC_CORE_INVALID &&
 			  core->state != VIDC_CORE_INVALID))
@@ -2835,9 +3159,9 @@
 
 	if (inst->state == MSM_VIDC_OPEN_DONE) {
 		num_mbs_per_sec = msm_comm_get_load(inst->core,
-					MSM_VIDC_DECODER);
+			MSM_VIDC_DECODER);
 		num_mbs_per_sec += msm_comm_get_load(inst->core,
-					MSM_VIDC_ENCODER);
+			MSM_VIDC_ENCODER);
 		if (num_mbs_per_sec > inst->core->resources.max_load) {
 			dprintk(VIDC_ERR,
 				"H/w is overloaded. needed: %d max: %d\n",
@@ -2852,6 +3176,71 @@
 	return 0;
 }
 
+
+int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst)
+{
+	u32 x_min, x_max, y_min, y_max;
+	u32 input_height, input_width, output_height, output_width;
+
+	if (!inst->capability.scale_x.min || !inst->capability.scale_x.max ||
+		!inst->capability.scale_y.min ||
+		!inst->capability.scale_y.max) {
+		dprintk(VIDC_ERR, "%s : Invalid scaling ratios",
+				__func__);
+		return -ENOTSUPP;
+	}
+	x_min = (1 << 16) / inst->capability.scale_x.min;
+	y_min = (1 << 16) / inst->capability.scale_y.min;
+	x_max = inst->capability.scale_x.max >> 16;
+	y_max = inst->capability.scale_y.max >> 16;
+
+	input_height = inst->prop.height[OUTPUT_PORT];
+	input_width = inst->prop.width[OUTPUT_PORT];
+	output_height = inst->prop.height[CAPTURE_PORT];
+	output_width = inst->prop.width[CAPTURE_PORT];
+
+	if (!input_height || !input_width || !output_height || !output_width) {
+		dprintk(VIDC_ERR,
+			"Invalid : Input Height = %d Width = %d"
+			" Output Height = %d Width = %d",
+			input_height, input_width, output_height,
+			output_width);
+		return -ENOTSUPP;
+	}
+
+	if (input_height > output_height) {
+		if (input_height / output_height > x_min) {
+			dprintk(VIDC_ERR,
+				"Unsupported Height Downscale ratio %d Vs %d",
+				input_height/output_height, x_min);
+			return -ENOTSUPP;
+		}
+	} else {
+		if (input_height / output_height > x_max) {
+			dprintk(VIDC_ERR,
+				"Unsupported Height Upscale ratio %d Vs %d",
+				input_height/output_height, x_max);
+			return -ENOTSUPP;
+		}
+	}
+	if (input_width > output_width) {
+		if (input_width / output_width > y_min) {
+			dprintk(VIDC_ERR,
+				"Unsupported Width Downscale ratio %d Vs %d",
+				input_width/output_width, y_min);
+			return -ENOTSUPP;
+		}
+	} else {
+		if (input_width / output_width > y_max) {
+			dprintk(VIDC_ERR,
+				"Unsupported Width Upscale ratio %d Vs %d",
+				input_width/output_width, y_max);
+			return -ENOTSUPP;
+		}
+	}
+	return 0;
+}
+
 int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
 {
 	struct msm_vidc_core_capability *capability;
@@ -2869,14 +3258,16 @@
 	if (!rc && inst->capability.capability_set) {
 		rc = call_hfi_op(hdev, capability_check,
 			inst->fmts[OUTPUT_PORT]->fourcc,
-			inst->prop.width, &capability->width.max,
+			inst->prop.width[CAPTURE_PORT], &capability->width.max,
 			&capability->height.max);
 
-		if (!rc && (inst->prop.height * inst->prop.width >
+		if (!rc && (inst->prop.height[CAPTURE_PORT]
+			* inst->prop.width[CAPTURE_PORT] >
 			capability->width.max * capability->height.max)) {
 			dprintk(VIDC_ERR,
 			"Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
-			inst->prop.width, inst->prop.height,
+			inst->prop.width[CAPTURE_PORT],
+			inst->prop.height[CAPTURE_PORT],
 			capability->width.max, capability->height.max);
 			rc = -ENOTSUPP;
 		}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index c018345..195fa7e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -31,6 +31,7 @@
 	enum hal_property ptype, void *pdata);
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_qbuf(struct vb2_buffer *vb);
 void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
@@ -47,5 +48,9 @@
 		(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
 		V4L2_CTRL_DRIVER_PRIV(idx))
 
-#endif
+int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst);
 int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 25651c9..5a18265 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -86,6 +86,18 @@
 	write_str(&dbg_buf, "irq: %u\n",
 		call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data,
 					FW_IRQ));
+	write_str(&dbg_buf, "clock count: %d\n",
+		call_hfi_op(hdev, get_info, hdev->hfi_device_data,
+					DEV_CLOCK_COUNT));
+	write_str(&dbg_buf, "clock enabled: %u\n",
+		call_hfi_op(hdev, get_info, hdev->hfi_device_data,
+					DEV_CLOCK_ENABLED));
+	write_str(&dbg_buf, "power count: %d\n",
+		call_hfi_op(hdev, get_info, hdev->hfi_device_data,
+					DEV_PWR_COUNT));
+	write_str(&dbg_buf, "power enabled: %u\n",
+		call_hfi_op(hdev, get_info, hdev->hfi_device_data,
+					DEV_PWR_ENABLED));
 	for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
 		write_str(&dbg_buf, "completions[%d]: %s\n", i,
 			completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index b17cb5a..2b1471c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -100,10 +100,18 @@
 	struct vb2_buffer *buf;
 };
 
+enum buffer_owner {
+	DRIVER,
+	FIRMWARE,
+	CLIENT,
+	MAX_OWNER
+};
+
 struct internal_buf {
 	struct list_head list;
 	enum hal_buffer buffer_type;
 	struct msm_smem *handle;
+	enum buffer_owner buffer_ownership;
 };
 
 struct msm_vidc_format {
@@ -128,8 +136,8 @@
 };
 
 struct session_prop {
-	u32 width;
-	u32 height;
+	u32 width[MAX_PORT_NUM];
+	u32 height[MAX_PORT_NUM];
 	u32 fps;
 	u32 bitrate;
 };
@@ -179,6 +187,9 @@
 	struct hal_capability_supported width;
 	struct hal_capability_supported height;
 	struct hal_capability_supported frame_rate;
+	u32 pixelprocess_capabilities;
+	struct hal_capability_supported scale_x;
+	struct hal_capability_supported scale_y;
 	u32 capability_set;
 	enum buffer_mode_type buffer_mode[MAX_PORT_NUM];
 };
@@ -211,6 +222,7 @@
 	struct list_head pendingq;
 	struct list_head internalbufs;
 	struct list_head persistbufs;
+	struct list_head outputbufs;
 	struct buffer_requirements buff_req;
 	void *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
@@ -229,6 +241,7 @@
 	struct msm_vidc_debug debug;
 	struct buf_count count;
 	enum msm_vidc_modes flags;
+	u32 multi_stream_mode;
 	struct msm_vidc_core_capability capability;
 	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
 	struct list_head registered_bufs;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index a5aebd5..916df1d 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -23,6 +23,7 @@
 #include <mach/ocmem.h>
 #include <mach/scm.h>
 #include <mach/subsystem_restart.h>
+#include <mach/msm_smem.h>
 #include <asm/memory.h>
 #include "hfi_packetization.h"
 #include "venus_hfi.h"
@@ -829,6 +830,7 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	++device->clk_cnt;
 	return 0;
 fail_clk_enable:
 	for (i--; i >= 0; i--) {
@@ -858,6 +860,7 @@
 		clk_disable(cl->clk);
 	}
 	device->clocks_enabled = 0;
+	--device->clk_cnt;
 }
 
 static DECLARE_COMPLETION(pc_prep_done);
@@ -899,6 +902,7 @@
 		venus_hfi_unvote_buses(device, DDR_MEM);
 
 	device->power_enabled = 0;
+	--device->pwr_cnt;
 already_disabled:
 	return rc;
 }
@@ -949,6 +953,7 @@
 		goto err_reset_core;
 	}
 	device->power_enabled = 1;
+	++device->pwr_cnt;
 	return rc;
 err_reset_core:
 	venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
@@ -2711,6 +2716,7 @@
 		clk_unprepare(cl->clk);
 	}
 	device->clocks_enabled = 0;
+	--device->clk_cnt;
 	mutex_unlock(&device->clk_pwr_lock);
 }
 static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
@@ -2736,6 +2742,7 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	++device->clk_cnt;
 	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 fail_clk_enable:
@@ -3206,6 +3213,7 @@
 		goto fail_load_fw;
 	}
 	device->power_enabled = 1;
+	++device->pwr_cnt;
 	mutex_unlock(&device->clk_pwr_lock);
 	/*Clocks can be enabled only after pil_get since
 	 * gdsc is turned-on in pil_get*/
@@ -3231,6 +3239,7 @@
 	device->resources.fw.cookie = NULL;
 	regulator_disable(device->gdsc);
 	device->power_enabled = 0;
+	--device->pwr_cnt;
 	mutex_unlock(&device->clk_pwr_lock);
 fail_enable_gdsc:
 	venus_hfi_iommu_detach(device);
@@ -3254,6 +3263,7 @@
 		subsystem_put(device->resources.fw.cookie);
 		regulator_disable(device->gdsc);
 		device->power_enabled = 0;
+		--device->pwr_cnt;
 		mutex_unlock(&device->clk_pwr_lock);
 		venus_hfi_interface_queues_release(dev);
 		venus_hfi_iommu_detach(device);
@@ -3295,6 +3305,37 @@
 	return rc;
 }
 
+static int venus_hfi_get_info(void *dev, enum dev_info info)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = dev;
+	if (!device) {
+		dprintk(VIDC_ERR, "%s Invalid parameter: %p\n",
+				__func__, device);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->clk_pwr_lock);
+	switch (info) {
+	case DEV_CLOCK_COUNT:
+		rc = device->clk_cnt;
+		break;
+	case DEV_CLOCK_ENABLED:
+		rc = device->clocks_enabled;
+		break;
+	case DEV_PWR_COUNT:
+		rc = device->pwr_cnt;
+		break;
+	case DEV_PWR_ENABLED:
+		rc = device->power_enabled;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid device info requested");
+	}
+	mutex_unlock(&device->clk_pwr_lock);
+	return rc;
+}
+
 int venus_hfi_get_stride_scanline(int color_fmt,
 	int width, int height, int *stride, int *scanlines) {
 	*stride = VENUS_Y_STRIDE(color_fmt, width);
@@ -3302,6 +3343,44 @@
 	return 0;
 }
 
+int venus_hfi_get_core_capabilities(void)
+{
+	int i = 0, rc = 0, j = 0, venus_version_length = 0;
+	u32 smem_block_size = 0;
+	u8 *smem_table_ptr;
+	char version[256];
+	const u32 version_string_size = 128;
+	char venus_version[] = "VIDEO.VE.1.4";
+	u8 version_info[256];
+	const u32 smem_image_index_venus = 14 * 128;
+	/* Venus version is stored at 14th entry in smem table */
+
+	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+			&smem_block_size);
+	if (smem_table_ptr &&
+			((smem_image_index_venus + version_string_size) <=
+			smem_block_size))
+		memcpy(version_info, smem_table_ptr + smem_image_index_venus,
+				version_string_size);
+
+	while (version_info[i++] != 'V' && i < version_string_size)
+		;
+
+	venus_version_length = strlen(venus_version);
+	for (i--, j = 0; i < version_string_size && j < venus_version_length;
+		i++)
+		version[j++] = version_info[i];
+	version[venus_version_length] = '\0';
+	dprintk(VIDC_DBG, "F/W version retrieved : %s\n", version);
+
+	if (strcmp((const char *)version, (const char *)venus_version) == 0)
+		rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
+			HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
+			HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
+			HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
+	return rc;
+}
+
 int venus_hfi_capability_check(u32 fourcc, u32 width,
 		u32 *max_width, u32 *max_height)
 {
@@ -3351,6 +3430,10 @@
 
 	hdevice->device_id = device_id;
 	hdevice->callback = callback;
+	hdevice->clocks_enabled = 0;
+	hdevice->clk_cnt = 0;
+	hdevice->power_enabled = 0;
+	hdevice->pwr_cnt = 0;
 
 	hdevice->vidc_workq = create_singlethread_workqueue(
 		"msm_vidc_workerq_venus");
@@ -3472,8 +3555,10 @@
 	hdev->load_fw = venus_hfi_load_fw;
 	hdev->unload_fw = venus_hfi_unload_fw;
 	hdev->get_fw_info = venus_hfi_get_fw_info;
+	hdev->get_info = venus_hfi_get_info;
 	hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
 	hdev->capability_check = venus_hfi_capability_check;
+	hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
 }
 
 int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index f1d8694..4feda45 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -207,6 +207,8 @@
 	u32 register_base;
 	u32 register_size;
 	u32 irq;
+	int clk_cnt;
+	int pwr_cnt;
 	struct venus_resources resources;
 	struct msm_vidc_platform_resources *res;
 	struct regulator *gdsc;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 1c9b71d..cc07806 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -186,6 +186,22 @@
 	HAL_UNUSED_DOMAIN = 0x10000000,
 };
 
+enum multi_stream {
+	HAL_VIDEO_DECODER_NONE = 0x00000000,
+	HAL_VIDEO_DECODER_PRIMARY = 0x00000001,
+	HAL_VIDEO_DECODER_SECONDARY = 0x00000002,
+	HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004,
+	HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000,
+};
+
+enum hal_core_capabilities {
+	HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001,
+	HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002,
+	HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY = 0x00000004,
+	HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY = 0x00000008,
+	HAL_VIDEO_UNUSED_CAPABILITY      = 0x10000000,
+};
+
 enum hal_video_codec {
 	HAL_VIDEO_CODEC_UNKNOWN  = 0x00000000,
 	HAL_VIDEO_CODEC_MVC      = 0x00000001,
@@ -1045,6 +1061,14 @@
 	FW_INFO_MAX,
 };
 
+enum dev_info {
+	DEV_CLOCK_COUNT,
+	DEV_CLOCK_ENABLED,
+	DEV_PWR_COUNT,
+	DEV_PWR_ENABLED,
+	DEV_INFO_MAX
+};
+
 #define call_hfi_op(q, op, args...)			\
 	(((q) && (q)->op) ? ((q)->op(args)) : 0)
 
@@ -1098,11 +1122,13 @@
 	int (*load_fw)(void *dev);
 	void (*unload_fw)(void *dev);
 	int (*get_fw_info)(void *dev, enum fw_info info);
+	int (*get_info) (void *dev, enum dev_info info);
 	int (*get_stride_scanline)(int color_fmt, int width,
 		int height,	int *stride, int *scanlines);
 	int (*capability_check)(u32 fourcc, u32 width,
 		u32 *max_width, u32 *max_height);
 	int (*session_clean)(void *sess);
+	int (*get_core_capabilities)(void);
 };
 
 typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 6589a7cf..1916e9f 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -438,6 +438,11 @@
 	u32 idr_period;
 };
 
+struct hfi_operations_type {
+	u32 rotation;
+	u32 flip;
+};
+
 struct hfi_max_num_b_frames {
 	u32 max_num_b_frames;
 };
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 5e056be..31d03b6 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -49,11 +49,15 @@
 static char utf_8_flag;
 static char rt_ert_flag;
 static char formatting_dir;
+static unsigned char sig_blend = CTRL_ON;
 static DEFINE_MUTEX(iris_fm);
 
 module_param(rds_buf, uint, 0);
 MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
 
+module_param(sig_blend, byte, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(sig_blend, "signal blending switch: 0:OFF 1:ON");
+
 static void radio_hci_cmd_task(unsigned long arg);
 static void radio_hci_rx_task(unsigned long arg);
 static struct video_device *video_get_dev(void);
@@ -4141,7 +4145,7 @@
 	}
 
 	radio->stereo_mode.stereo_mode = CTRL_OFF;
-	radio->stereo_mode.sig_blend = CTRL_ON;
+	radio->stereo_mode.sig_blend = sig_blend;
 	radio->stereo_mode.intf_blend = CTRL_ON;
 	radio->stereo_mode.most_switch = CTRL_ON;
 	retval = hci_set_fm_stereo_mode(&radio->stereo_mode,
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 4a8d974..9dd06ee 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -284,6 +284,7 @@
 		"4.2",
 		"5",
 		"5.1",
+		"5.2",
 		NULL,
 	};
 	static const char * const h264_loop_filter[] = {
@@ -597,6 +598,8 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: return "Intra Refresh CIR MBS";
 	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
 		return "VP8 Profile Level";
+	case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE:
+		return "Deinterlace for encoder";
 
 	/* CAMERA controls */
 	/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -806,6 +809,16 @@
 		*min = 0;
 		*max = *step = 1;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE:
+		*type = V4L2_CTRL_TYPE_BOOLEAN;
+		*min = 0;
+		*max = *step = 1;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+		*type = V4L2_CTRL_TYPE_BOOLEAN;
+		*min = 0;
+		*max = *step = 1;
+		break;
 	default:
 		*type = V4L2_CTRL_TYPE_INTEGER;
 		break;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index d8abc6d..907ce7c 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -544,8 +544,10 @@
 	{WCD9XXX_IRQ_PA2_STARTUP, false},
 	{WCD9XXX_IRQ_PA3_STARTUP, false},
 	{WCD9XXX_IRQ_PA4_STARTUP, false},
+	{WCD9306_IRQ_HPH_PA_OCPR_FAULT, false},
 	{WCD9XXX_IRQ_PA5_STARTUP, false},
 	{WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+	{WCD9306_IRQ_HPH_PA_OCPL_FAULT, false},
 	{WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
 	{WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
 	{WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index dc32efd..9209f0b 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -150,13 +150,15 @@
 				      msm_cpuidle_get_deep_idle_latency());
 	}
 	mutex_unlock(&wcd9xxx_res->pm_lock);
-	os = wcd9xxx_pm_cmpxchg(wcd9xxx_res,
-					WCD9XXX_PM_SLEEPABLE,
-					WCD9XXX_PM_AWAKE);
+
 	if (!wait_event_timeout(wcd9xxx_res->pm_wq,
-			(os  == WCD9XXX_PM_SLEEPABLE ||
-			 os == WCD9XXX_PM_AWAKE),
-			msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+				((os =  wcd9xxx_pm_cmpxchg(wcd9xxx_res,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_AWAKE)) ==
+							WCD9XXX_PM_SLEEPABLE ||
+					(os == WCD9XXX_PM_AWAKE)),
+				msecs_to_jiffies(
+					WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
 		pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
 			__func__,
 			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx_res->pm_state,
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index e5315bd..743668b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2800,8 +2800,11 @@
  err_putdisk:
 	put_disk(md->disk);
  err_kfree:
+	if (!subname)
+		__clear_bit(md->name_idx, name_use);
 	kfree(md);
  out:
+	__clear_bit(devidx, dev_use);
 	return ERR_PTR(ret);
 }
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 89e3472..95f0a04 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -516,8 +516,6 @@
 
 	if (mrq->data)
 		mrq->data->bytes_xfered = host->curr.data_xfered;
-	if (mrq->cmd->error == -ETIMEDOUT)
-		mdelay(5);
 
 	msmsdcc_reset_dpsm(host);
 
@@ -6475,7 +6473,7 @@
 	host->debugfs_host_dir = NULL;
 }
 #else
-static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
+static void msmsdcc_remove_debugfs(struct msmsdcc_host *host) {}
 #endif
 
 static int msmsdcc_remove(struct platform_device *pdev)
@@ -6682,7 +6680,7 @@
 }
 #endif
 
-#if CONFIG_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
 static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
 				   const char *func, int err)
 {
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2c8598b..b93eaf4 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2310,6 +2310,7 @@
 	struct sdhci_msm_host *msm_host = pltfm_host->priv;
 	struct mmc_ios	curr_ios = host->mmc->ios;
 	u32 sup_clock, ddr_clock;
+	bool curr_pwrsave;
 
 	if (!clock) {
 		sdhci_msm_prepare_clocks(host, false);
@@ -2321,6 +2322,22 @@
 	if (rc)
 		return;
 
+	curr_pwrsave = !!(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+			  CORE_CLK_PWRSAVE);
+	if ((clock > 400000) &&
+	    !curr_pwrsave && mmc_host_may_gate_card(host->mmc->card))
+		writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+				| CORE_CLK_PWRSAVE,
+				host->ioaddr + CORE_VENDOR_SPEC);
+	/*
+	 * Disable pwrsave for a newly added card if doesn't allow clock
+	 * gating.
+	 */
+	else if (curr_pwrsave && !mmc_host_may_gate_card(host->mmc->card))
+		writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+				& ~CORE_CLK_PWRSAVE,
+				host->ioaddr + CORE_VENDOR_SPEC);
+
 	sup_clock = sdhci_msm_get_sup_clk_rate(host, clock);
 	if ((curr_ios.timing == MMC_TIMING_UHS_DDR50) ||
 		(curr_ios.timing == MMC_TIMING_MMC_HS400)) {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0cb0491..758a79e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -110,7 +110,7 @@
 		sdhci_readl(host, SDHCI_INT_ENABLE),
 		sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
 	pr_info(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-		sdhci_readw(host, SDHCI_AUTO_CMD_ERR),
+		host->auto_cmd_err_sts,
 		sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
 	pr_info(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
 		sdhci_readl(host, SDHCI_CAPABILITIES),
@@ -2375,6 +2375,7 @@
 	host->mrq = NULL;
 	host->cmd = NULL;
 	host->data = NULL;
+	host->auto_cmd_err_sts = 0;
 
 #ifndef SDHCI_USE_LEDS_CLASS
 	sdhci_deactivate_led(host);
@@ -2465,7 +2466,9 @@
 		host->cmd->error = -EILSEQ;
 
 	if (intmask & SDHCI_INT_AUTO_CMD_ERR) {
-		auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_ERR);
+		auto_cmd_status = host->auto_cmd_err_sts;
+		pr_err("%s: %s: AUTO CMD err sts 0x%08x\n",
+			mmc_hostname(host->mmc), __func__, auto_cmd_status);
 		if (auto_cmd_status & (SDHCI_AUTO_CMD12_NOT_EXEC |
 				       SDHCI_AUTO_CMD_INDEX_ERR |
 				       SDHCI_AUTO_CMD_ENDBIT_ERR))
@@ -2728,6 +2731,9 @@
 	}
 
 	if (intmask & SDHCI_INT_CMD_MASK) {
+		if (intmask & SDHCI_INT_AUTO_CMD_ERR)
+			host->auto_cmd_err_sts = sdhci_readw(host,
+					SDHCI_AUTO_CMD_ERR);
 		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
 			SDHCI_INT_STATUS);
 		if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5ccdd2a..0a408b1 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -314,6 +314,16 @@
 	---help---
 	  Pre-allocate memory for the WLAN driver module
 
+config WCNSS_REGISTER_DUMP_ON_BITE
+	bool "Enable/disable WCNSS register dump when there is a WCNSS bite"
+	depends on WCNSS_CORE_PRONTO
+	help
+	 When Apps recieves a WDOG bite from WCNSS, collecting a register dump
+	 of WCNSS is helpful to root cause the failure. WCNSS may not be
+	 properly clocked in some WCNSS bite cases, and that may cause unclocked
+	 register access failures. So this feature is to enable/disable the
+	 register dump on WCNSS WDOG bite.
+
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/b43/Kconfig"
 source "drivers/net/wireless/b43legacy/Kconfig"
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 64d1478..7b743a4 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -648,6 +648,14 @@
 }
 EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
 
+#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
+void wcnss_log_debug_regs_on_bite(void)
+{
+	if (wcnss_hardware_type() == WCNSS_PRONTO_HW)
+		wcnss_pronto_log_debug_regs();
+}
+#endif
+
 /* interface to reset wcnss by sending the reset interrupt */
 void wcnss_reset_intr(void)
 {
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index c0371a5..50d5f7b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -107,6 +107,7 @@
 	u32 bark_irq;
 	u16 s2_cntl_addr;
 	u16 s2_cntl2_addr;
+	bool use_bark;
 };
 
 struct qpnp_pon {
@@ -614,7 +615,7 @@
 							cfg->state_irq);
 			return rc;
 		}
-		if (cfg->support_reset) {
+		if (cfg->use_bark) {
 			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
 						qpnp_kpdpwr_bark_irq,
 						IRQF_TRIGGER_RISING,
@@ -637,7 +638,7 @@
 							cfg->state_irq);
 			return rc;
 		}
-		if (cfg->support_reset) {
+		if (cfg->use_bark) {
 			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
 						qpnp_resin_bark_irq,
 						IRQF_TRIGGER_RISING,
@@ -662,7 +663,7 @@
 		}
 		break;
 	case PON_KPDPWR_RESIN:
-		if (cfg->support_reset) {
+		if (cfg->use_bark) {
 			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
 					qpnp_kpdpwr_resin_bark_irq,
 					IRQF_TRIGGER_RISING,
@@ -755,7 +756,9 @@
 				return rc;
 			}
 
-			if (cfg->support_reset) {
+			cfg->use_bark = of_property_read_bool(pp,
+							"qcom,use-bark");
+			if (cfg->use_bark) {
 				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
 							NULL, "kpdpwr-bark");
 				if (cfg->bark_irq < 0) {
@@ -793,7 +796,9 @@
 				return rc;
 			}
 
-			if (cfg->support_reset) {
+			cfg->use_bark = of_property_read_bool(pp,
+							"qcom,use-bark");
+			if (cfg->use_bark) {
 				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
 							NULL, "resin-bark");
 				if (cfg->bark_irq < 0) {
@@ -832,7 +837,9 @@
 				return rc;
 			}
 
-			if (cfg->support_reset) {
+			cfg->use_bark = of_property_read_bool(pp,
+							"qcom,use-bark");
+			if (cfg->use_bark) {
 				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
 						NULL, "kpdpwr-resin-bark");
 				if (cfg->bark_irq < 0) {
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 4be727f..8bb4f90 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -356,7 +356,7 @@
 		/*
 		 * Enable USB PRIVATE RAM to be used for BAM FIFOs
 		 * HSUSB: Only RAM13 is used for BAM FIFOs
-		 * SSUSB: RAM12, 13 are used for BAM FIFOs
+		 * SSUSB: RAM11, 12, 13 are used for BAM FIFOs
 		 */
 		bam = pipe_connect->bam_type;
 		if (bam < 0)
@@ -365,7 +365,7 @@
 		if (bam == HSUSB_BAM)
 			ram1_value = 0x4;
 		else
-			ram1_value = 0x6;
+			ram1_value = 0x7;
 
 		pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
 		writel_relaxed(ram1_value, ctx.qscratch_ram1_reg);
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 04620c2..915767d 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -105,6 +105,7 @@
 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CHARGE_FULL,
 	POWER_SUPPLY_PROP_TEMP,
@@ -171,6 +172,13 @@
 
 		val->intval = ret * 625 / 8;
 		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		ret = max17042_read_reg(chip->client, MAX17042_OCVInternal);
+		if (ret < 0)
+			return ret;
+
+		val->intval = ret * 625 / 8;
+		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
 		ret = max17042_read_reg(chip->client, MAX17042_RepSOC);
 		if (ret < 0)
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 319a24d..b918110 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -148,6 +148,7 @@
 	POWER_SUPPLY_ATTR(voltage_now),
 	POWER_SUPPLY_ATTR(voltage_avg),
 	POWER_SUPPLY_ATTR(input_voltage_regulation),
+	POWER_SUPPLY_ATTR(voltage_ocv),
 	POWER_SUPPLY_ATTR(current_max),
 	POWER_SUPPLY_ATTR(input_current_max),
 	POWER_SUPPLY_ATTR(input_current_trim),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index ad39e88..5904cec 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -209,6 +209,7 @@
 
 	uint16_t			ocv_reading_at_100;
 	uint16_t			prev_last_good_ocv_raw;
+	int				insertion_ocv_uv;
 	int				last_ocv_uv;
 	int				charging_adjusted_ocv;
 	int				last_ocv_temp;
@@ -239,6 +240,7 @@
 	unsigned int			vadc_v0625;
 	unsigned int			vadc_v1250;
 
+	int				system_load_count;
 	int				prev_uuc_iavg_ma;
 	int				prev_pc_unusable;
 	int				ibat_at_cv_ua;
@@ -769,7 +771,7 @@
 	if (chip->batt_psy == NULL)
 		chip->batt_psy = power_supply_get_by_name("battery");
 	if (chip->batt_psy) {
-		/* if battery has been registered, use the status property */
+		/* if battery has been registered, use the present property */
 		chip->batt_psy->get_property(chip->batt_psy,
 					POWER_SUPPLY_PROP_PRESENT, &ret);
 		return ret.intval;
@@ -780,6 +782,35 @@
 	return false;
 }
 
+static int get_battery_insertion_ocv_uv(struct qpnp_bms_chip *chip)
+{
+	union power_supply_propval ret = {0,};
+	int rc, vbat;
+
+	if (chip->batt_psy == NULL)
+		chip->batt_psy = power_supply_get_by_name("battery");
+	if (chip->batt_psy) {
+		/* if battery has been registered, use the ocv property */
+		rc = chip->batt_psy->get_property(chip->batt_psy,
+				POWER_SUPPLY_PROP_VOLTAGE_OCV, &ret);
+		if (rc) {
+			/*
+			 * Default to vbatt if the battery OCV is not
+			 * registered.
+			 */
+			pr_debug("Battery psy does not have voltage ocv\n");
+			rc = get_battery_voltage(chip, &vbat);
+			if (rc)
+				return -EINVAL;
+			return vbat;
+		}
+		return ret.intval;
+	}
+
+	pr_debug("battery power supply is not registered\n");
+	return -EINVAL;
+}
+
 static bool is_batfet_closed(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
@@ -859,7 +890,7 @@
 
 static void reset_for_new_battery(struct qpnp_bms_chip *chip, int batt_temp)
 {
-	chip->last_ocv_uv = estimate_ocv(chip);
+	chip->last_ocv_uv = chip->insertion_ocv_uv;
 	mutex_lock(&chip->last_soc_mutex);
 	chip->last_soc = -EINVAL;
 	chip->last_soc_invalid = true;
@@ -896,7 +927,7 @@
 				struct raw_soc_params *raw,
 				int batt_temp)
 {
-	bool warm_reset = false;
+	int warm_reset;
 	int rc;
 
 	mutex_lock(&chip->bms_output_lock);
@@ -1302,48 +1333,79 @@
 	return uuc_uah_iavg;
 }
 
-static void find_ocv_for_soc(struct qpnp_bms_chip *chip,
-				struct soc_params *params,
-				int batt_temp,
-				int shutdown_soc,
-				int *ret_ocv_uv)
+static s64 find_ocv_charge_for_soc(struct qpnp_bms_chip *chip,
+				struct soc_params *params, int soc)
 {
-	s64 ocv_charge_uah;
-	int pc, new_pc;
-	int batt_temp_degc = batt_temp / 10;
-	int ocv_uv;
+	return div_s64((s64)soc * (params->fcc_uah - params->uuc_uah),
+			100) + params->cc_uah + params->uuc_uah;
+}
 
-	ocv_charge_uah = (s64)shutdown_soc
-				* (params->fcc_uah - params->uuc_uah);
-	ocv_charge_uah = div_s64(ocv_charge_uah, 100)
-				+ params->cc_uah + params->uuc_uah;
+static int find_pc_for_soc(struct qpnp_bms_chip *chip,
+			struct soc_params *params, int soc)
+{
+	int ocv_charge_uah = find_ocv_charge_for_soc(chip, params, soc);
+	int pc;
+
 	pc = DIV_ROUND_CLOSEST((int)ocv_charge_uah * 100, params->fcc_uah);
 	pc = clamp(pc, 0, 100);
+	pr_debug("soc = %d, fcc = %d uuc = %d rc = %d pc = %d\n",
+			soc, params->fcc_uah, params->uuc_uah,
+			ocv_charge_uah, pc);
+	return pc;
+}
 
-	ocv_uv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+#define UV_PER_SPIN 50000
+static int find_ocv_for_pc(struct qpnp_bms_chip *chip, int batt_temp, int pc)
+{
+	int new_pc;
+	int batt_temp_degc = batt_temp / 10;
+	int ocv_mv;
+	int delta_mv = 5;
+	int max_spin_count;
+	int count = 0;
+	int sign, new_sign;
 
-	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
-					shutdown_soc, params->fcc_uah,
-					params->uuc_uah, (int)ocv_charge_uah,
-					pc, ocv_uv);
-	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_uv);
-	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_uv);
+	ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
 
-	while (abs(new_pc - pc) > 1) {
-		int delta_mv = 5;
+	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_mv);
+	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_mv);
+	max_spin_count = 1 + (chip->max_voltage_uv - chip->v_cutoff_uv)
+						/ UV_PER_SPIN;
+	sign = SIGN(pc - new_pc);
 
-		if (new_pc > pc)
-			delta_mv = -1 * delta_mv;
+	while (abs(new_pc - pc) != 0 && count < max_spin_count) {
+		/*
+		 * If the newly interpolated pc is larger than the lookup pc,
+		 * the ocv should be reduced and vice versa
+		 */
+		new_sign = SIGN(pc - new_pc);
+		/*
+		 * If the sign has changed, then we have passed the lookup pc.
+		 * reduce the ocv step size to get finer results.
+		 *
+		 * If we have already reduced the ocv step size and still
+		 * passed the lookup pc, just stop and use the current ocv.
+		 * This can only happen if the batterydata profile is
+		 * non-monotonic anyways.
+		 */
+		if (new_sign != sign) {
+			if (delta_mv > 1)
+				delta_mv = 1;
+			else
+				break;
+		}
+		sign = new_sign;
 
-		ocv_uv = ocv_uv + delta_mv;
+		ocv_mv = ocv_mv + delta_mv * sign;
 		new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
-				batt_temp_degc, ocv_uv);
+				batt_temp_degc, ocv_mv);
 		pr_debug("test revlookup pc = %d for ocv = %d\n",
-				new_pc, ocv_uv);
+			new_pc, ocv_mv);
+		count++;
 	}
 
-	*ret_ocv_uv = ocv_uv * 1000;
-	params->ocv_charge_uah = (int)ocv_charge_uah;
+	return ocv_mv * 1000;
 }
 
 static int get_current_time(unsigned long *now_tm_sec)
@@ -1798,14 +1860,14 @@
 		return report_cc_based_soc(chip);
 }
 
-#define VDD_MAX_ERR		5000
-#define VDD_STEP_SIZE		10000
+#define VDD_MAX_ERR			5000
+#define VDD_STEP_SIZE			10000
+#define MAX_COUNT_BEFORE_RESET_TO_CC	3
 static int charging_adjustments(struct qpnp_bms_chip *chip,
 				struct soc_params *params, int soc,
 				int vbat_uv, int ibat_ua, int batt_temp)
 {
 	int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
-	int new_ocv_uv;
 
 	batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
 
@@ -1822,9 +1884,28 @@
 		}
 
 		chip->prev_batt_terminal_uv = batt_terminal_uv;
+		chip->system_load_count = 0;
+		return soc;
+	} else if (ibat_ua > 0 && batt_terminal_uv
+			< chip->max_voltage_uv - (VDD_MAX_ERR * 2)) {
+		if (chip->system_load_count > MAX_COUNT_BEFORE_RESET_TO_CC) {
+			chip->soc_at_cv = -EINVAL;
+			pr_debug("Vbat below CV threshold, resetting CC_TO_CV\n");
+			chip->system_load_count = 0;
+		} else {
+			chip->system_load_count += 1;
+			pr_debug("Vbat below CV threshold, count: %d\n",
+					chip->system_load_count);
+		}
+		return soc;
+	} else if (ibat_ua > 0) {
+		pr_debug("NOT CHARGING SOC %d\n", soc);
+		chip->system_load_count = 0;
+		chip->prev_chg_soc = soc;
 		return soc;
 	}
 
+	chip->system_load_count = 0;
 	/*
 	 * battery is in CV phase - begin linear interpolation of soc based on
 	 * battery charge current
@@ -1859,9 +1940,10 @@
 	if (chg_soc > chip->prev_chg_soc) {
 		chip->prev_chg_soc = chg_soc;
 
-		find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
-		chip->charging_adjusted_ocv = new_ocv_uv;
-		pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n", new_ocv_uv,
+		chip->charging_adjusted_ocv = find_ocv_for_pc(chip, batt_temp,
+				find_pc_for_soc(chip, params, chg_soc));
+		pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
+				chip->charging_adjusted_ocv,
 				chip->prev_chg_soc);
 	}
 
@@ -1951,10 +2033,12 @@
 		goto out;
 	}
 
-	if (ibat_ua < 0 && !is_battery_full(chip)) {
+	if (is_battery_charging(chip)) {
 		soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
 				batt_temp);
-		goto out;
+		/* Skip adjustments if we are in CV or ibat is negative */
+		if (chip->soc_at_cv != -EINVAL || ibat_ua < 0)
+			goto out;
 	}
 
 	/*
@@ -2143,7 +2227,8 @@
 	cc_raw_64 = convert_cc_uah_to_raw(chip, target_cc_uah);
 	cc_raw = convert_s64_to_s36(cc_raw_64);
 
-	find_ocv_for_soc(chip, params, batt_temp, target_soc, &target_ocv_uv);
+	target_ocv_uv = find_ocv_for_pc(chip, batt_temp,
+				find_pc_for_soc(chip, params, target_soc));
 	ocv_raw = convert_vbatt_uv_to_raw(chip, target_ocv_uv);
 
 	/*
@@ -2173,8 +2258,7 @@
 					struct soc_params *params,
 					int batt_temp)
 {
-	int soc, new_ocv_uv;
-	int remaining_usable_charge_uah;
+	int soc, remaining_usable_charge_uah;
 
 	/* calculate remaining usable charge */
 	remaining_usable_charge_uah = params->ocv_charge_uah
@@ -2191,8 +2275,10 @@
 		 * in a bad soc. Adjust ocv to get 0 soc
 		 */
 		pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
-		find_ocv_for_soc(chip, params, batt_temp, 0, &new_ocv_uv);
-		chip->last_ocv_uv = new_ocv_uv;
+		chip->last_ocv_uv = find_ocv_for_pc(chip, batt_temp,
+				find_pc_for_soc(chip, params, 0));
+		params->ocv_charge_uah = find_ocv_charge_for_soc(chip,
+				params, 0);
 
 		remaining_usable_charge_uah = params->ocv_charge_uah
 					- params->cc_uah
@@ -2230,7 +2316,7 @@
 {
 	struct soc_params params;
 	int soc, previous_soc, shutdown_soc, new_calculated_soc;
-	int remaining_usable_charge_uah, new_ocv_uv;
+	int remaining_usable_charge_uah;
 
 	calculate_soc_params(chip, raw, &params, batt_temp);
 	if (!is_battery_present(chip)) {
@@ -2261,9 +2347,10 @@
 		 */
 		pr_debug("soc = %d before forcing shutdown_soc = %d\n",
 							soc, shutdown_soc);
-		find_ocv_for_soc(chip, &params, batt_temp,
-					shutdown_soc, &new_ocv_uv);
-		chip->last_ocv_uv = new_ocv_uv;
+		chip->last_ocv_uv = find_ocv_for_pc(chip, batt_temp,
+				find_pc_for_soc(chip, &params, shutdown_soc));
+		params.ocv_charge_uah = find_ocv_charge_for_soc(chip,
+				&params, shutdown_soc);
 
 		remaining_usable_charge_uah = params.ocv_charge_uah
 					- params.cc_uah
@@ -3171,12 +3258,20 @@
 
 static void battery_insertion_check(struct qpnp_bms_chip *chip)
 {
-	bool present = is_battery_present(chip);
+	int present = (int)is_battery_present(chip);
+	int insertion_ocv_uv = get_battery_insertion_ocv_uv(chip);
+	int insertion_ocv_taken = (insertion_ocv_uv > 0);
 
 	mutex_lock(&chip->vbat_monitor_mutex);
-	if (chip->battery_present != present) {
+	if (chip->battery_present != present
+			&& (present == insertion_ocv_taken
+				|| chip->battery_present == -EINVAL)) {
+		pr_debug("status = %d, shadow status = %d, insertion_ocv_uv = %d\n",
+				present, chip->battery_present,
+				insertion_ocv_uv);
 		if (chip->battery_present != -EINVAL) {
 			if (present) {
+				chip->insertion_ocv_uv = insertion_ocv_uv;
 				setup_vbat_monitoring(chip);
 				chip->new_battery = true;
 			} else {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 64ad940..8d94b88 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -325,6 +325,7 @@
 	unsigned int			warm_bat_mv;
 	unsigned int			cool_bat_mv;
 	unsigned int			resume_delta_mv;
+	int				insertion_ocv_uv;
 	int				term_current;
 	int				soc_resume_limit;
 	bool				resuming_charging;
@@ -354,6 +355,7 @@
 	struct delayed_work		usbin_health_check;
 	struct work_struct		soc_check_work;
 	struct delayed_work		aicl_check_work;
+	struct work_struct		insertion_ocv_work;
 	struct qpnp_chg_regulator	otg_vreg;
 	struct qpnp_chg_regulator	boost_vreg;
 	struct qpnp_chg_regulator	batfet_vreg;
@@ -965,6 +967,11 @@
 static int
 qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
 {
+	if (chip->insertion_ocv_uv == 0 && enable) {
+		pr_debug("Battery not present, skipping\n");
+		return 0;
+	}
+	pr_debug("charging %s\n", enable ? "enabled" : "disabled");
 	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
 			CHGR_CHG_EN,
 			enable ? CHGR_CHG_EN : 0, 1);
@@ -1476,6 +1483,12 @@
 	pr_debug("batt-pres triggered: %d\n", batt_present);
 
 	if (chip->batt_present ^ batt_present) {
+		if (batt_present) {
+			schedule_work(&chip->insertion_ocv_work);
+		} else {
+			chip->insertion_ocv_uv = 0;
+			qpnp_chg_charge_en(chip, 0);
+		}
 		chip->batt_present = batt_present;
 		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
@@ -1507,6 +1520,8 @@
 
 	if (chip->dc_present ^ dc_present) {
 		chip->dc_present = dc_present;
+		if (qpnp_chg_is_otg_en_set(chip))
+			qpnp_chg_force_run_on_batt(chip, !dc_present ? 1 : 0);
 		if (!dc_present && !qpnp_chg_is_usb_chg_plugged_in(chip)) {
 			chip->delta_vddmax_mv = 0;
 			qpnp_chg_set_appropriate_vddmax(chip);
@@ -1711,10 +1726,12 @@
 	if (qpnp_chg_is_otg_en_set(chip))
 		return 0;
 
-	rc = qpnp_chg_force_run_on_batt(chip, 1);
-	if (rc) {
-		pr_err("Failed to disable charging rc = %d\n", rc);
-		return rc;
+	if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
+		rc = qpnp_chg_force_run_on_batt(chip, 1);
+		if (rc) {
+			pr_err("Failed to disable charging rc = %d\n", rc);
+			return rc;
+		}
 	}
 
 	/* force usb ovp fet off */
@@ -1760,6 +1777,7 @@
 	POWER_SUPPLY_PROP_WARM_TEMP,
 	POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
 	POWER_SUPPLY_PROP_CYCLE_COUNT,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
 };
 
 static char *pm_power_supplied_to[] = {
@@ -2180,6 +2198,9 @@
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		val->intval = get_prop_battery_voltage_now(chip);
 		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		val->intval = chip->insertion_ocv_uv;
+		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		val->intval = get_prop_batt_temp(chip);
 		break;
@@ -2888,6 +2909,32 @@
 }
 
 static void
+qpnp_chg_insertion_ocv_work(struct work_struct *work)
+{
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, insertion_ocv_work);
+	u8 bat_if_sts = 0, charge_en = 0;
+	int rc;
+
+	chip->insertion_ocv_uv = get_prop_battery_voltage_now(chip);
+
+	rc = qpnp_chg_read(chip, &bat_if_sts, INT_RT_STS(chip->bat_if_base), 1);
+	if (rc)
+		pr_err("failed to read bat_if sts %d\n", rc);
+
+	rc = qpnp_chg_read(chip, &charge_en,
+			chip->chgr_base + CHGR_CHG_CTRL, 1);
+	if (rc)
+		pr_err("failed to read bat_if sts %d\n", rc);
+
+	pr_debug("batfet sts = %02x, charge_en = %02x ocv = %d\n",
+			bat_if_sts, charge_en, chip->insertion_ocv_uv);
+	qpnp_chg_charge_en(chip, !chip->charging_disabled);
+	pr_debug("psy changed batt_psy\n");
+	power_supply_changed(&chip->batt_psy);
+}
+
+static void
 qpnp_chg_soc_check_work(struct work_struct *work)
 {
 	struct qpnp_chg_chip *chip = container_of(work,
@@ -4137,6 +4184,8 @@
 	mutex_init(&chip->batfet_vreg_lock);
 	INIT_WORK(&chip->batfet_lcl_work,
 			qpnp_chg_batfet_lcl_work);
+	INIT_WORK(&chip->insertion_ocv_work,
+			qpnp_chg_insertion_ocv_work);
 
 	/* Get all device tree properties */
 	rc = qpnp_charger_read_dt_props(chip);
@@ -4317,6 +4366,8 @@
 	dev_set_drvdata(&spmi->dev, chip);
 	device_init_wakeup(&spmi->dev, 1);
 
+	chip->insertion_ocv_uv = -EINVAL;
+	chip->batt_present = qpnp_chg_is_batt_present(chip);
 	if (chip->bat_if_base) {
 		chip->batt_psy.name = "battery";
 		chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 4512d02..45400cb 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -652,8 +652,6 @@
 	if (dd->qup_ver == SPI_QUP_VERSION_NONE)
 		/* flags removed from SPI_CONFIG in QUP version-2 */
 		msm_spi_set_bpw_and_no_io_flags(dd, &spi_config, bpw-1);
-	else if (dd->mode == SPI_BAM_MODE)
-		spi_config |= SPI_CFG_INPUT_FIRST;
 
 	/*
 	 * HS_MODE improves signal stability for spi-clk high rates
diff --git a/drivers/spmi/spmi-dbgfs.h b/drivers/spmi/spmi-dbgfs.h
index 10e98b9..a419002 100644
--- a/drivers/spmi/spmi-dbgfs.h
+++ b/drivers/spmi/spmi-dbgfs.h
@@ -18,8 +18,14 @@
 int spmi_dfs_add_controller(struct spmi_controller *ctrl);
 int spmi_dfs_del_controller(struct spmi_controller *ctrl);
 #else
-static int spmi_dfs_add_controller(struct spmi_controller *ctrl) { return 0; }
-static int spmi_dfs_del_controller(struct spmi_controller *ctrl) { return 0; }
+static inline int spmi_dfs_add_controller(struct spmi_controller *ctrl)
+{
+	return 0;
+}
+static inline int spmi_dfs_del_controller(struct spmi_controller *ctrl)
+{
+	return 0;
+}
 #endif
 
 struct dentry *spmi_dfs_create_file(struct spmi_controller *ctrl,
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 674efb3..068dd5f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -780,6 +780,7 @@
 	bool			softconnect;
 	void (*notify_event) (struct dwc3 *, unsigned);
 	int			tx_fifo_size;
+	bool			tx_fifo_reduced;
 };
 
 /* -------------------------------------------------------------------------- */
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 60d7119..784ff3f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -69,6 +69,10 @@
 module_param(override_phy_init, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(override_phy_init, "Override HSPHY Init Seq");
 
+static int ss_phy_override_deemphasis;
+module_param(ss_phy_override_deemphasis, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ss_phy_override_deemphasis, "Override SSPHY demphasis value");
+
 /* Enable Proprietary charger detection */
 static bool prop_chg_detect;
 module_param(prop_chg_detect, bool, S_IRUGO | S_IWUSR);
@@ -198,6 +202,7 @@
 	atomic_t		in_lpm;
 	int			hs_phy_irq;
 	int			hsphy_init_seq;
+	int			deemphasis_val;
 	bool			lpm_irq_seen;
 	struct delayed_work	resume_work;
 	struct work_struct	restart_usb_work;
@@ -1037,10 +1042,13 @@
 	struct dwc3 *dwc = dep->dwc;
 	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
 
-	if (qdss_enabled)
+	if (qdss_enabled) {
+		dwc->tx_fifo_reduced = true;
 		dwc->tx_fifo_size = mdwc->qdss_tx_fifo_size;
-	else
+	} else {
+		dwc->tx_fifo_reduced = false;
 		dwc->tx_fifo_size = mdwc->tx_fifo_size;
+	}
 }
 EXPORT_SYMBOL(dwc3_tx_fifo_resize_request);
 
@@ -1416,7 +1424,12 @@
 	 */
 	data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1002);
 	data &= ~0x3F80;
-	data |= (0x16 << 7);
+	if (ss_phy_override_deemphasis)
+		mdwc->deemphasis_val = ss_phy_override_deemphasis;
+	if (mdwc->deemphasis_val)
+		data |= (mdwc->deemphasis_val << 7);
+	else
+		data |= (0x16 << 7);
 	data &= ~0x7F;
 	data |= (0x7F | (1 << 14));
 	dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1002, data);
@@ -2978,6 +2991,10 @@
 	else if (!mdwc->hsphy_init_seq)
 		dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
 
+	if (of_property_read_u32(node, "qcom,dwc-ssphy-deemphasis-value",
+						&mdwc->deemphasis_val))
+		dev_dbg(&pdev->dev, "unable to read ssphy deemphasis value\n");
+
 	pm_runtime_set_active(mdwc->dev);
 	pm_runtime_enable(mdwc->dev);
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8588ffb..38c4b86 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -229,14 +229,20 @@
 		tmp = mult * (dep->endpoint.maxpacket + mdwidth);
 
 		if (dwc->tx_fifo_size &&
-				(usb_endpoint_xfer_bulk(dep->endpoint.desc)
-				|| usb_endpoint_xfer_isoc(dep->endpoint.desc)))
+			(usb_endpoint_xfer_bulk(dep->endpoint.desc)
+			|| usb_endpoint_xfer_isoc(dep->endpoint.desc))) {
 			/*
 			 * Allocate 3KB fifo size for bulk and isochronous TX
-			 * endpoints irrespective of speed. For interrupt
-			 * endpoint, allocate fifo size of endpoint maxpacket.
+			 * endpoints irrespective of speed if tx_fifo is not
+			 * reduced. Otherwise allocate 1KB for endpoints in HS
+			 * mode and for non burst endpoints in SS mode. For
+			 * interrupt ep, allocate fifo size of ep maxpacket.
 			 */
-			tmp = 3 * (1024 + mdwidth);
+			if (!dwc->tx_fifo_reduced)
+				tmp = 3 * (1024 + mdwidth);
+			else
+				tmp = mult * (1024 + mdwidth);
+		}
 
 		tmp += mdwidth;
 
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index e4fb26a..7d63bf9 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1356,6 +1356,14 @@
 			if (c && c->setup)
 				value = c->setup(c, ctrl);
 		}
+		if (value == USB_GADGET_DELAYED_STATUS) {
+			DBG(cdev,
+			 "%s: interface %d (%s) requested delayed status\n",
+					__func__, intf, f->name);
+			cdev->delayed_status++;
+			DBG(cdev, "delayed_status count %d\n",
+					cdev->delayed_status);
+		}
 
 		goto done;
 	}
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index bccc504..effe0fd 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -837,17 +837,28 @@
 struct dentry *dent_diag;
 static void fdiag_debugfs_init(void)
 {
+	struct dentry *dent_diag_status;
 	dent_diag = debugfs_create_dir("usb_diag", 0);
-	if (IS_ERR(dent_diag))
+	if (!dent_diag || IS_ERR(dent_diag))
 		return;
 
-	debugfs_create_file("status", 0444, dent_diag, 0, &debug_fdiag_ops);
+	dent_diag_status = debugfs_create_file("status", 0444, dent_diag, 0,
+			&debug_fdiag_ops);
+
+	if (!dent_diag_status || IS_ERR(dent_diag_status)) {
+		debugfs_remove(dent_diag);
+		dent_diag = NULL;
+		return;
+	}
+}
+
+static void fdiag_debugfs_remove(void)
+{
+	debugfs_remove_recursive(dent_diag);
 }
 #else
-static void fdiag_debugfs_init(void)
-{
-	return;
-}
+static inline void fdiag_debugfs_init(void) {}
+static inline void fdiag_debugfs_remove(void) {}
 #endif
 
 static void diag_cleanup(void)
@@ -856,7 +867,7 @@
 	struct usb_diag_ch *_ch;
 	unsigned long flags;
 
-	debugfs_remove_recursive(dent_diag);
+	fdiag_debugfs_remove();
 
 	list_for_each_safe(act, tmp, &usb_diag_ch_list) {
 		_ch = list_entry(act, struct usb_diag_ch, list);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 2f35315..4410e99 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -637,7 +637,10 @@
 		 */
 		DBG(fsg, "bulk reset request\n");
 		raise_exception(fsg->common, FSG_STATE_RESET);
-		return DELAYED_STATUS;
+		if (fsg->common->cdev)
+			return USB_GADGET_DELAYED_STATUS;
+		else
+			return DELAYED_STATUS;
 
 	case US_BULK_GET_MAX_LUN:
 		if (ctrl->bRequestType !=
@@ -2698,8 +2701,13 @@
 				       &common->fsg->atomic_bitflags))
 			usb_ep_clear_halt(common->fsg->bulk_in);
 
-		if (common->ep0_req_tag == exception_req_tag)
-			ep0_queue(common);	/* Complete the status stage */
+		if (common->ep0_req_tag == exception_req_tag) {
+			/* Complete the status stage */
+			if (common->cdev)
+				usb_composite_setup_continue(common->cdev);
+			else
+				ep0_queue(common);
+		}
 
 		/*
 		 * Technically this should go here, but it would only be
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 6bfa203..2fa8c63 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -1219,6 +1219,7 @@
 	for (i = 0; i < nr_rmnet_ports; i++)
 		kfree(rmnet_ports[i].port);
 
+	gbam_cleanup();
 	nr_rmnet_ports = 0;
 	no_ctrl_smd_ports = 0;
 	no_ctrl_qti_ports = 0;
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index 8aec34f..74a8062 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -5,7 +5,7 @@
  * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
  * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
  * Copyright (C) 2008 Nokia Corporation
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1267,19 +1267,17 @@
 };
 
 struct dentry *dent_smd;
-struct dentry *dent_smd_status;
-
 static void rmnet_smd_debugfs_init(struct rmnet_smd_dev *dev)
 {
-
+	struct dentry *dent_smd_status;
 	dent_smd = debugfs_create_dir("usb_rmnet_smd", 0);
-	if (IS_ERR(dent_smd))
+	if (!dent_smd || IS_ERR(dent_smd))
 		return;
 
 	dent_smd_status = debugfs_create_file("status", 0444, dent_smd, dev,
 			&rmnet_smd_debug_stats_ops);
 
-	if (!dent_smd_status) {
+	if (!dent_smd_status || IS_ERR(dent_smd_status)) {
 		debugfs_remove(dent_smd);
 		dent_smd = NULL;
 		return;
@@ -1287,8 +1285,14 @@
 
 	return;
 }
+
+static void rmnet_smd_debugfs_remove(void)
+{
+	debugfs_remove_recursive(dent_smd);
+}
 #else
-static void rmnet_smd_debugfs_init(struct rmnet_smd_dev *dev) {}
+static inline void rmnet_smd_debugfs_init(struct rmnet_smd_dev *dev) {}
+static inline void rmnet_smd_debugfs_remove(void){}
 #endif
 
 static void
@@ -1307,7 +1311,9 @@
 	dev->epout = dev->epin = dev->epnotify = NULL; /* release endpoints */
 
 	destroy_workqueue(dev->wq);
-	debugfs_remove_recursive(dent_smd);
+
+	rmnet_smd_debugfs_remove();
+
 	kfree(dev);
 
 }
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index aa6c99a..2fc758d 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -5,7 +5,7 @@
  * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
  * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
  * Copyright (C) 2008 Nokia Corporation
- * Copyright (c) 2011 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011,2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1758,16 +1758,28 @@
 
 static void rmnet_mux_debugfs_init(struct rmnet_mux_dev *dev)
 {
-
+	struct dentry *dent_rmnet_mux_status;
 	dent_rmnet_mux = debugfs_create_dir("usb_rmnet_mux", 0);
-	if (IS_ERR(dent_rmnet_mux))
+	if (!dent_rmnet_mux || IS_ERR(dent_rmnet_mux))
 		return;
 
-	debugfs_create_file("status", 0444, dent_rmnet_mux, dev,
+	dent_rmnet_mux_status = debugfs_create_file("status",
+			0444, dent_rmnet_mux, dev,
 			&rmnet_mux_svlte_debug_stats_ops);
+	if (!dent_rmnet_mux_status) {
+		debugfs_remove(dent_rmnet_mux);
+		dent_rmnet_mux = NULL;
+		return;
+	}
+}
+
+static void rmnet_mux_debugfs_remove(void)
+{
+	debugfs_remove_recursive(dent_rmnet_mux);
 }
 #else
-static void rmnet_mux_debugfs_init(struct rmnet_mux_dev *dev) {}
+static inline void rmnet_mux_debugfs_init(struct rmnet_mux_dev *dev) {}
+static inline void rmnet_mux_debugfs_remove(void) {}
 #endif
 
 int usb_rmnet_mux_ctrl_open(struct inode *inode, struct file *fp)
@@ -2037,7 +2049,7 @@
 	struct rmnet_mux_dev *dev = rmux_dev;
 	struct rmnet_mux_smd_dev *smd_dev = &dev->smd_dev;
 
-	debugfs_remove_recursive(dent_rmnet_mux);
+	rmnet_mux_debugfs_remove();
 	misc_deregister(&rmnet_mux_ctrl_dev);
 	smd_close(smd_dev->smd_data.ch);
 	destroy_workqueue(dev->wq);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index b0b2f56..843c207 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -1281,22 +1281,30 @@
 	.write = gbam_reset_stats,
 };
 
+struct dentry *gbam_dent;
 static void gbam_debugfs_init(void)
 {
-	struct dentry *dent;
 	struct dentry *dfile;
 
-	dent = debugfs_create_dir("usb_rmnet", 0);
-	if (IS_ERR(dent))
+	gbam_dent = debugfs_create_dir("usb_rmnet", 0);
+	if (!gbam_dent || IS_ERR(gbam_dent))
 		return;
 
-	/* TODO: Implement cleanup function to remove created file */
-	dfile = debugfs_create_file("status", 0444, dent, 0, &gbam_stats_ops);
-	if (!dfile || IS_ERR(dfile))
-		debugfs_remove(dent);
+	dfile = debugfs_create_file("status", 0444, gbam_dent, 0,
+			&gbam_stats_ops);
+	if (!dfile || IS_ERR(dfile)) {
+		debugfs_remove(gbam_dent);
+		gbam_dent = NULL;
+		return;
+	}
+}
+static void gbam_debugfs_remove(void)
+{
+	debugfs_remove_recursive(gbam_dent);
 }
 #else
-static void gam_debugfs_init(void) { }
+static inline void gbam_debugfs_init(void) {}
+static inline void gbam_debugfs_remove(void) {}
 #endif
 
 void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1445,7 +1453,6 @@
 
 	d->trans = trans;
 	queue_work(gbam_wq, &port->connect_w);
-
 	return 0;
 }
 
@@ -1490,6 +1497,7 @@
 			goto free_bam_ports;
 		}
 	}
+
 	gbam_debugfs_init();
 	return 0;
 
@@ -1503,6 +1511,11 @@
 	return ret;
 }
 
+void gbam_cleanup(void)
+{
+	gbam_debugfs_remove();
+}
+
 void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
 {
 	struct gbam_port	*port;
diff --git a/drivers/usb/gadget/u_ctrl_hsuart.c b/drivers/usb/gadget/u_ctrl_hsuart.c
index 3443d12..b57e4e3 100644
--- a/drivers/usb/gadget/u_ctrl_hsuart.c
+++ b/drivers/usb/gadget/u_ctrl_hsuart.c
@@ -479,6 +479,7 @@
 	return ret;
 }
 
+#if defined(CONFIG_DEBUG_FS)
 #define DEBUG_BUF_SIZE	1024
 static ssize_t ghsuart_ctrl_read_stats(struct file *file, char __user *ubuf,
 		size_t count, loff_t *ppos)
@@ -558,7 +559,7 @@
 
 	ghsuart_ctrl_dfile =
 		debugfs_create_file("status", S_IRUGO | S_IWUSR,
-				ghsuart_ctrl_dent, 0, &gctrl_stats_ops);
+				ghsuart_ctrl_dent, 0, &ghsuart_ctrl_stats_ops);
 	if (!ghsuart_ctrl_dfile || IS_ERR(ghsuart_ctrl_dfile)) {
 		debugfs_remove(ghsuart_ctrl_dent);
 		ghsuart_ctrl_dent = NULL;
@@ -571,6 +572,10 @@
 {
 	debugfs_remove_recursive(ghsuart_ctrl_dent);
 }
+#else
+static int ghsuart_ctrl_debugfs_init(void) { return 0; }
+static void ghsuart_ctrl_debugfs_exit(void) {}
+#endif
 
 static int __init ghsuart_ctrl_init(void)
 {
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 06471a4..6a80529 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -54,6 +54,7 @@
 };
 
 int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
+void gbam_cleanup(void);
 int gbam_connect(struct grmnet *gr, u8 port_num,
 	enum transport_type trans, u8 src_connection_idx,
 	u8 dst_connection_idx);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 350e723..299f620c 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
  * Copyright (C) 2008 David Brownell
  * Copyright (C) 2008 by Nokia Corporation
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This code also borrows from usbserial.c, which is
  * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
@@ -1294,22 +1295,29 @@
 	.read = debug_read_status,
 };
 
+struct dentry *gs_dent;
 static void usb_debugfs_init(struct gs_port *ui_dev, int port_num)
 {
-	struct dentry *dent;
 	char buf[48];
 
 	snprintf(buf, 48, "usb_serial%d", port_num);
-	dent = debugfs_create_dir(buf, 0);
-	if (IS_ERR(dent))
+	gs_dent = debugfs_create_dir(buf, 0);
+	if (!gs_dent || IS_ERR(gs_dent))
 		return;
 
-	debugfs_create_file("readstatus", 0444, dent, ui_dev, &debug_adb_ops);
+	debugfs_create_file("readstatus", 0444, gs_dent, ui_dev,
+			&debug_adb_ops);
 	debugfs_create_file("reset", S_IRUGO | S_IWUSR,
-			dent, ui_dev, &debug_rst_ops);
+			gs_dent, ui_dev, &debug_rst_ops);
+}
+
+static void usb_debugfs_remove(void)
+{
+	debugfs_remove_recursive(gs_dent);
 }
 #else
-static void usb_debugfs_init(struct gs_port *ui_dev) {}
+static inline void usb_debugfs_init(struct gs_port *ui_dev, int port_num) {}
+static inline void usb_debugfs_remove(void) {}
 #endif
 
 /**
@@ -1474,6 +1482,7 @@
 	}
 	n_ports = 0;
 
+	usb_debugfs_remove();
 	destroy_workqueue(gserial_wq);
 	tty_unregister_driver(gs_tty_driver);
 	put_tty_driver(gs_tty_driver);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4cf4703..276bbb0 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -882,6 +882,7 @@
 	if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
 		return -EBUSY;
 
+	motg->ui_enabled = 0;
 	disable_irq(motg->irq);
 	host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
 		!test_bit(ID, &motg->inputs);
@@ -912,6 +913,7 @@
 	if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
 		!dcp && !prop_charger && !floated_charger) ||
 		test_bit(A_BUS_REQ, &motg->inputs)) {
+		motg->ui_enabled = 1;
 		enable_irq(motg->irq);
 		return -EBUSY;
 	}
@@ -961,6 +963,7 @@
 	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
 		dev_err(phy->dev, "Unable to suspend PHY\n");
 		msm_otg_reset(phy);
+		motg->ui_enabled = 1;
 		enable_irq(motg->irq);
 		return -ETIMEDOUT;
 	}
@@ -1077,7 +1080,12 @@
 	/* Enable ASYNC IRQ (if present) during LPM */
 	if (motg->async_irq)
 		enable_irq(motg->async_irq);
-	enable_irq(motg->irq);
+
+	/* XO shutdown during idle , non wakeable irqs must be disabled */
+	if (device_bus_suspend || host_bus_suspend || !motg->async_irq) {
+		motg->ui_enabled = 1;
+		enable_irq(motg->irq);
+	}
 	wake_unlock(&motg->wlock);
 
 	dev_info(phy->dev, "USB in low power mode\n");
@@ -1101,7 +1109,10 @@
 	if (motg->pdata->delay_lpm_hndshk_on_disconnect)
 		msm_bam_notify_lpm_resume();
 
-	disable_irq(motg->irq);
+	if (motg->ui_enabled) {
+		motg->ui_enabled = 0;
+		disable_irq(motg->irq);
+	}
 	wake_lock(&motg->wlock);
 
 	/* Some platforms require BUS vote to enable/disable clocks */
@@ -1206,6 +1217,7 @@
 		enable_irq(motg->async_int);
 		motg->async_int = 0;
 	}
+	motg->ui_enabled = 1;
 	enable_irq(motg->irq);
 
 	/* If ASYNC IRQ is present then keep it enabled only during LPM */
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 5264005..e416a55 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -547,7 +547,6 @@
 	for (i = 0; i < cnt; i++) {
 		dsi_buf_init(tp);
 		dsi_cmd_dma_add(tp, cm);
-		msm_dsi_cmd_dma_tx(tp);
 		rc = msm_dsi_cmd_dma_tx(tp);
 		if (IS_ERR_VALUE(rc)) {
 			pr_err("%s: failed to call cmd_dma_tx\n", __func__);
@@ -591,6 +590,17 @@
 {
 	int cnt, len, diff, pkt_size, rc = 0;
 	char cmd;
+	unsigned char *ctrl_base = dsi_host_private->dsi_base;
+	u32 dsi_ctrl, data;
+	int video_mode;
+
+	/* turn on cmd mode for video mode */
+	dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
+	video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+	if (video_mode) {
+		data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+		MIPI_OUTP(ctrl_base + DSI_CTRL, data);
+	}
 
 	if (pdata->panel_info.mipi.no_max_pkt_size)
 		rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
@@ -699,6 +709,9 @@
 		break;
 	}
 
+	if (video_mode)
+		MIPI_OUTP(ctrl_base + DSI_CTRL,
+					dsi_ctrl); /* restore */
 end:
 	return rp->len;
 }
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 55037e3..638fcb3 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -586,41 +586,6 @@
 	return 0;
 }
 
-struct reg_dump {
-	int start_addr;
-	int num_reads;
-};
-
-struct reg_dump ppp_reg[] = {
-	{0x10108, 3},
-	{0x10118, 6},
-	{0x10138, 9},
-	{0x10158, 1},
-	{0x10164, 7},
-	{0x1019C, 1},
-	{0x101b8, 2},
-	{0x101c0, 8},
-};
-
-static int mdp3_iommu_fault_handler(struct iommu_domain *domain,
-		struct device *dev, unsigned long iova, int flags, void *token)
-{
-	unsigned int addr, val;
-	int i, j;
-	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
-	for (i = 0; i < ARRAY_SIZE(ppp_reg); i++) {
-		for (j = 0; j < ppp_reg[i].num_reads; j++) {
-			addr = ppp_reg[i].start_addr + (j*4);
-			val = MDP3_REG_READ(addr);
-			pr_err("TMsg: Addr= 0x%08x, val= 0x%08x\n",
-				(unsigned int)addr, (unsigned int)val);
-		}
-	}
-	panic("PPP pagefault, shutting down for easier debugging\n");
-	return 0;
-}
-
-
 int mdp3_iommu_attach(int context)
 {
 	struct mdp3_iommu_ctx_map *context_map;
@@ -696,9 +661,6 @@
 			else
 				return PTR_ERR(mdp3_iommu_domains[i].domain);
 		}
-		iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
-			mdp3_iommu_fault_handler,
-			NULL);
 	}
 
 	mdp3_res->domains = mdp3_iommu_domains;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 8f6168a..d16cb3f 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -502,7 +502,6 @@
 
 	src_w = req->src_rect.w;
 	dst_h = blit_op->dst.roi.height;
-	pr_err("TMsg: In workaround. srcw= %d, dstH=%d\n", src_w, dst_h);
 	/* bg tile fetching HW workaround */
 	for (i = 0; i < (req->dst_rect.h / 16); i++) {
 		/* this tile size */
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 3bf27e2..61c4acd 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -28,6 +28,8 @@
 #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)
 
+#define MAX_DRV_SUP_MMB_BLKS	44
+
 enum mdss_mdp_clk_type {
 	MDSS_CLK_AHB,
 	MDSS_CLK_AXI,
@@ -69,6 +71,8 @@
 	struct clk *mdp_clk[MDSS_MAX_CLK];
 	struct regulator *fs;
 	struct regulator *vdd_cx;
+	bool batfet_required;
+	struct regulator *batfet;
 	u32 max_mdp_clk_rate;
 
 	struct platform_device *pdev;
@@ -111,6 +115,9 @@
 	u32 nvig_pipes;
 	u32 nrgb_pipes;
 	u32 ndma_pipes;
+
+	DECLARE_BITMAP(mmb_alloc_map, MAX_DRV_SUP_MMB_BLKS);
+
 	struct mdss_mdp_mixer *mixer_intf;
 	struct mdss_mdp_mixer *mixer_wb;
 	u32 nmixers_intf;
@@ -158,6 +165,7 @@
 void mdss_enable_irq(struct mdss_hw *hw);
 void mdss_disable_irq(struct mdss_hw *hw);
 void mdss_disable_irq_nosync(struct mdss_hw *hw);
+void mdss_bus_bandwidth_ctrl(int enable);
 
 static inline struct ion_client *mdss_get_ionclient(void)
 {
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index b353c96..865775a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -751,7 +751,9 @@
 		mdss_dsi_clk_req(ctrl_pdata, (int)arg);
 		break;
 	case MDSS_EVENT_DSI_CMDLIST_KOFF:
+		ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg;
 		mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
+		break;
 	case MDSS_EVENT_PANEL_UPDATE_FPS:
 		if (arg != NULL) {
 			rc = mdss_dsi_dfps_config(pdata, (int)arg);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 121d6ff..f950f41 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -307,6 +307,10 @@
 	DSI_CTRL_MAX,
 };
 
+#define DSI_EV_PLL_UNLOCKED		0x0001
+#define DSI_EV_MDP_FIFO_UNDERFLOW	0x0002
+#define DSI_EV_MDP_BUSY_RELEASE		0x80000000
+
 struct mdss_dsi_ctrl_pdata {
 	int ndx;	/* panel_num */
 	int (*on) (struct mdss_panel_data *pdata);
@@ -316,6 +320,7 @@
 	unsigned char *ctrl_base;
 	int reg_size;
 	u32 clk_cnt;
+	struct clk *mdp_core_clk;
 	struct clk *ahb_clk;
 	struct clk *axi_clk;
 	struct clk *byte_clk;
@@ -339,6 +344,7 @@
 	int pwm_lpg_chan;
 	int bklt_max;
 	int new_fps;
+	int pwm_enabled;
 	struct pwm_device *pwm_bl;
 	struct dsi_drv_cm_data shared_pdata;
 	u32 pclk_rate;
@@ -346,6 +352,7 @@
 	struct dss_module_power power_data;
 	u32 dsi_irq_mask;
 	struct mdss_hw *dsi_hw;
+	struct mdss_panel_recovery *recovery;
 
 	struct dsi_panel_cmds on_cmds;
 	struct dsi_panel_cmds off_cmds;
@@ -388,7 +395,7 @@
 void mdp4_dsi_cmd_trigger(void);
 void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
-void mdss_dsi_ack_err_status(unsigned char *dsi_base);
+void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl);
 int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
 void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
 				int enable);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 62bc7e6..8711791 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -19,11 +19,13 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/iopoll.h>
+#include <linux/kthread.h>
 
 #include <mach/iommu_domains.h>
 
 #include "mdss.h"
 #include "mdss_dsi.h"
+#include "mdss_panel.h"
 
 #define VSYNC_PERIOD 17
 
@@ -44,6 +46,28 @@
 	.irq_handler = mdss_dsi_isr,
 };
 
+
+#define DSI_EVENT_Q_MAX	4
+
+/* event */
+struct dsi_event_q {
+	struct mdss_dsi_ctrl_pdata *ctrl;
+	u32 todo;
+};
+
+struct mdss_dsi_event {
+	int inited;
+	wait_queue_head_t event_q;
+	u32 event_pndx;
+	u32 event_gndx;
+	struct dsi_event_q todo_list[DSI_EVENT_Q_MAX];
+	spinlock_t event_lock;
+};
+
+static struct mdss_dsi_event dsi_event;
+
+static int dsi_event_thread(void *data);
+
 void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	if (ctrl->shared_pdata.broadcast_enable)
@@ -80,6 +104,13 @@
 	mutex_init(&ctrl->cmd_mutex);
 	mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
 	mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
+
+
+	if (dsi_event.inited == 0) {
+		kthread_run(dsi_event_thread, (void *)&dsi_event,
+						"mdss_dsi_event");
+		dsi_event.inited  = 1;
+	}
 }
 
 void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
@@ -94,6 +125,21 @@
 	mdss_dsi_clk_ctrl(ctrl, enable);
 }
 
+void mdss_dsi_pll_relock(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	int i, cnt;
+
+	cnt = ctrl->clk_cnt;
+
+	/* disable dsi clk */
+	for (i = 0; i < cnt; i++)
+		mdss_dsi_clk_ctrl(ctrl, 0);
+
+	/* enable dsi clk */
+	for (i = 0; i < cnt; i++)
+		mdss_dsi_clk_ctrl(ctrl, 1);
+}
+
 void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
 {
 	unsigned long flags;
@@ -942,6 +988,50 @@
 	wmb();
 }
 
+void mdss_dsi_sw_reset_restore(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	u32 data0, data1;
+
+	data0 = MIPI_INP(ctrl->ctrl_base + 0x0004);
+	data1 = data0;
+	data1 &= ~0x01;
+	MIPI_OUTP(ctrl->ctrl_base + 0x0004, data1);
+	/*
+	 * dsi controller need to be disabled before
+	 * clocks turned on
+	 */
+	wmb();	/* make sure dsi contoller is disabled */
+
+	/* turn esc, byte, dsi, pclk, sclk, hclk on */
+	MIPI_OUTP(ctrl->ctrl_base + 0x11c, 0x23f); /* DSI_CLK_CTRL */
+	wmb();	/* make sure clocks enabled */
+
+	/* dsi controller can only be reset while clocks are running */
+	MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x01);
+	wmb();	/* make sure reset happen */
+	MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x00);
+	wmb();	/* controller out of reset */
+	MIPI_OUTP(ctrl->ctrl_base + 0x0004, data0);
+	wmb();	/* make sure dsi controller enabled again */
+}
+
+void mdss_dsi_err_intr_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask,
+					int enable)
+{
+	u32 intr;
+
+	intr = MIPI_INP(ctrl->ctrl_base + 0x0110);
+
+	if (enable)
+		intr |= mask;
+	else
+		intr &= ~mask;
+
+	pr_debug("%s: intr=%x enable=%d\n", __func__, intr, enable);
+
+	MIPI_OUTP(ctrl->ctrl_base + 0x0110, intr); /* DSI_INTL_CTRL */
+}
+
 void mdss_dsi_controller_cfg(int enable,
 			     struct mdss_panel_data *pdata)
 {
@@ -1072,7 +1162,7 @@
 				0, timeout_us))
 		pr_info("%s: DSI status=%x failed\n", __func__, status);
 
-	mdss_dsi_ack_err_status((ctrl_pdata->ctrl_base));
+	mdss_dsi_ack_err_status(ctrl_pdata);
 
 	pr_debug("%s: BTA done, status = %d\n", __func__, status);
 }
@@ -1674,6 +1764,14 @@
 	if (req == NULL)
 		goto need_lock;
 
+	/*
+	 * mdss interrupt is generated in mdp core clock domain
+	 * mdp clock need to be enabled to receive dsi interrupt
+	 * also, axi bus bandwidth need since dsi controller will
+	 * fetch dcs commands from axi bus
+	 */
+	mdss_bus_bandwidth_ctrl(1);
+
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
 	mdss_dsi_clk_ctrl(ctrl, 1);
 
@@ -1683,6 +1781,7 @@
 		mdss_dsi_cmdlist_tx(ctrl, req);
 
 	mdss_dsi_clk_ctrl(ctrl, 0);
+	mdss_bus_bandwidth_ctrl(0);
 
 need_lock:
 
@@ -1746,9 +1845,89 @@
 	return ret;
 }
 
-void mdss_dsi_ack_err_status(unsigned char *base)
+
+static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
+{
+	struct dsi_event_q *evq;
+
+	if (!dsi_event.inited)
+		return;
+
+	pr_debug("%s: ev=%x\n", __func__, events);
+
+	spin_lock(&dsi_event.event_lock);
+	evq = &dsi_event.todo_list[dsi_event.event_pndx++];
+	evq->todo = events;
+	evq->ctrl = ctrl;
+	dsi_event.event_pndx %= DSI_EVENT_Q_MAX;
+	wake_up(&dsi_event.event_q);
+	spin_unlock(&dsi_event.event_lock);
+}
+
+static int dsi_event_thread(void *data)
+{
+	struct mdss_dsi_event *ev;
+	struct dsi_event_q *evq;
+	struct mdss_dsi_ctrl_pdata *ctrl;
+	unsigned long flag;
+	struct sched_param param;
+	u32 todo = 0;
+	int ret;
+
+	param.sched_priority = 16;
+	ret = sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
+	if (ret)
+		pr_err("%s: set priority failed\n", __func__);
+
+	ev = (struct mdss_dsi_event *)data;
+	/* event */
+	init_waitqueue_head(&ev->event_q);
+	spin_lock_init(&ev->event_lock);
+
+	while (1) {
+		wait_event(ev->event_q, (ev->event_pndx != ev->event_gndx));
+		spin_lock_irqsave(&ev->event_lock, flag);
+		evq = &ev->todo_list[ev->event_gndx++];
+		todo = evq->todo;
+		ctrl = evq->ctrl;
+		evq->todo = 0;
+		ev->event_gndx %= DSI_EVENT_Q_MAX;
+		spin_unlock_irqrestore(&ev->event_lock, flag);
+
+		pr_debug("%s: ev=%x\n", __func__, todo);
+
+		if (todo & DSI_EV_PLL_UNLOCKED)
+			mdss_dsi_pll_relock(ctrl);
+
+		if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) {
+			if (ctrl->recovery) {
+				mdss_dsi_sw_reset_restore(ctrl);
+				ctrl->recovery->fxn(ctrl->recovery->data);
+			}
+		}
+
+		if (todo & DSI_EV_MDP_BUSY_RELEASE) {
+			spin_lock(&ctrl->mdp_lock);
+			ctrl->mdp_busy = false;
+			mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+			complete(&ctrl->mdp_comp);
+			spin_unlock(&ctrl->mdp_lock);
+
+			/* enable dsi error interrupt */
+			mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1);
+		}
+
+	}
+
+	return 0;
+}
+
+void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	u32 status;
+	unsigned char *base;
+
+	base = ctrl->ctrl_base;
 
 	status = MIPI_INP(base + 0x0068);/* DSI_ACK_ERR_STATUS */
 
@@ -1758,20 +1937,27 @@
 	}
 }
 
-void mdss_dsi_timeout_status(unsigned char *base)
+void mdss_dsi_timeout_status(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	u32 status;
+	unsigned char *base;
+
+	base = ctrl->ctrl_base;
 
 	status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */
+
 	if (status & 0x0111) {
 		MIPI_OUTP(base + 0x00c0, status);
 		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_dln0_phy_err(unsigned char *base)
+void mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	u32 status;
+	unsigned char *base;
+
+	base = ctrl->ctrl_base;
 
 	status = MIPI_INP(base + 0x00b4);/* DSI_DLN0_PHY_ERR */
 
@@ -1781,44 +1967,70 @@
 	}
 }
 
-void mdss_dsi_fifo_status(unsigned char *base)
+void mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	u32 status;
+	unsigned char *base;
+
+	base = ctrl->ctrl_base;
 
 	status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */
 
-	if (status & 0x44444489) {
+	/* fifo underflow, overflow */
+	if (status & 0xcccc4489) {
 		MIPI_OUTP(base + 0x000c, status);
 		pr_err("%s: status=%x\n", __func__, status);
+		if (status & 0x0080)  /* CMD_DMA_FIFO_UNDERFLOW */
+			dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW);
+	}
+}
+
+void mdss_dsi_status(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	u32 status;
+	unsigned char *base;
+
+	base = ctrl->ctrl_base;
+
+	status = MIPI_INP(base + 0x0008);/* DSI_STATUS */
+
+	if (status & 0x80000000) { /* INTERLEAVE_OP_CONTENTION */
+		MIPI_OUTP(base + 0x0008, status);
+		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_status(unsigned char *base)
+void mdss_dsi_clk_status(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	u32 status;
+	unsigned char *base;
 
-	status = MIPI_INP(base + 0x0008);/* DSI_STATUS */
+	base = ctrl->ctrl_base;
+	status = MIPI_INP(base + 0x0120);/* DSI_CLK_STATUS */
 
-	if (status & 0x80000000) {
-		MIPI_OUTP(base + 0x0008, status);
+	if (status & 0x10000) { /* DSI_CLK_PLL_UNLOCKED */
+		MIPI_OUTP(base + 0x0120, status);
+		dsi_send_events(ctrl, DSI_EV_PLL_UNLOCKED);
 		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
 
 void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	unsigned char *base;
 
-	base = ctrl->ctrl_base;
+	/* disable dsi error interrupt */
+	mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 0);
 
 	/* DSI_ERR_INT_MASK0 */
-	mdss_dsi_ack_err_status(base);	/* mask0, 0x01f */
-	mdss_dsi_timeout_status(base);	/* mask0, 0x0e0 */
-	mdss_dsi_fifo_status(base);		/* mask0, 0x133d00 */
-	mdss_dsi_status(base);		/* mask0, 0xc0100 */
-	mdss_dsi_dln0_phy_err(base);	/* mask0, 0x3e00000 */
-}
+	mdss_dsi_clk_status(ctrl);	/* Mask0, 0x10000000 */
+	mdss_dsi_fifo_status(ctrl);	/* mask0, 0x133d00 */
+	mdss_dsi_ack_err_status(ctrl);	/* mask0, 0x01f */
+	mdss_dsi_timeout_status(ctrl);	/* mask0, 0x0e0 */
+	mdss_dsi_status(ctrl);		/* mask0, 0xc0100 */
+	mdss_dsi_dln0_phy_err(ctrl);	/* mask0, 0x3e00000 */
 
+	dsi_send_events(ctrl, DSI_EV_MDP_BUSY_RELEASE);
+}
 
 irqreturn_t mdss_dsi_isr(int irq, void *ptr)
 {
@@ -1846,12 +2058,7 @@
 
 	if (isr & DSI_INTR_ERROR) {
 		pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
-		spin_lock(&ctrl->mdp_lock);
-		ctrl->mdp_busy = false;
-		mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
-		complete(&ctrl->mdp_comp);
 		mdss_dsi_error(ctrl);
-		spin_unlock(&ctrl->mdp_lock);
 	}
 
 	if (isr & DSI_INTR_VIDEO_DONE) {
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 262b7bd..33109e1 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -66,6 +66,13 @@
 		return;
 	}
 
+	if (level == 0) {
+		if (ctrl->pwm_enabled)
+			pwm_disable(ctrl->pwm_bl);
+		ctrl->pwm_enabled = 0;
+		return;
+	}
+
 	duty = level * ctrl->pwm_period;
 	duty /= ctrl->bklt_max;
 
@@ -76,6 +83,11 @@
 	pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
 					ctrl->ndx, level, duty);
 
+	if (ctrl->pwm_enabled) {
+		pwm_disable(ctrl->pwm_bl);
+		ctrl->pwm_enabled = 0;
+	}
+
 	ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
 	if (ret) {
 		pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
@@ -85,6 +97,7 @@
 	ret = pwm_enable(ctrl->pwm_bl);
 	if (ret)
 		pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
+	ctrl->pwm_enabled = 1;
 }
 
 static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */
@@ -182,14 +195,15 @@
 	pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	if (enable) {
+		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+
 		for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
 			gpio_set_value((ctrl_pdata->rst_gpio),
 				pdata->panel_info.rst_seq[i]);
 			if (pdata->panel_info.rst_seq[++i])
 				usleep(pdata->panel_info.rst_seq[i] * 1000);
 		}
-		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
 
 		if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
 			if (pinfo->mode_gpio_state == MODE_GPIO_HIGH)
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 64caaf5..042491d 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -164,46 +164,33 @@
 	ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
 			"qcom,panel-pwm-period", &edp_drv->pwm_period);
 	if (ret) {
-		pr_err("%s: panel pwm period is not specified, %d", __func__,
+		pr_warn("%s: panel pwm period is not specified, %d", __func__,
 				edp_drv->pwm_period);
-		return -EINVAL;
+		edp_drv->pwm_period = -EINVAL;
 	}
 
 	ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
 			"qcom,panel-lpg-channel", &edp_drv->lpg_channel);
 	if (ret) {
-		pr_err("%s: panel lpg channel is not specified, %d", __func__,
+		pr_warn("%s: panel lpg channel is not specified, %d", __func__,
 				edp_drv->lpg_channel);
-		return -EINVAL;
+		edp_drv->lpg_channel = -EINVAL;
 	}
 
-	edp_drv->bl_pwm = pwm_request(edp_drv->lpg_channel, "lcd-backlight");
-	if (edp_drv->bl_pwm == NULL || IS_ERR(edp_drv->bl_pwm)) {
-		pr_err("%s: pwm request failed", __func__);
+	if (edp_drv->pwm_period != -EINVAL &&
+		edp_drv->lpg_channel != -EINVAL) {
+		edp_drv->bl_pwm = pwm_request(edp_drv->lpg_channel,
+				"lcd-backlight");
+		if (edp_drv->bl_pwm == NULL || IS_ERR(edp_drv->bl_pwm)) {
+			pr_err("%s: pwm request failed", __func__);
+			edp_drv->bl_pwm = NULL;
+			return -EIO;
+		}
+	} else {
 		edp_drv->bl_pwm = NULL;
-		return -EIO;
-	}
-
-	edp_drv->gpio_panel_pwm = of_get_named_gpio(edp_drv->pdev->dev.of_node,
-			"gpio-panel-pwm", 0);
-	if (!gpio_is_valid(edp_drv->gpio_panel_pwm)) {
-		pr_err("%s: gpio_panel_pwm=%d not specified\n", __func__,
-				edp_drv->gpio_panel_pwm);
-		goto edp_free_pwm;
-	}
-
-	ret = gpio_request(edp_drv->gpio_panel_pwm, "disp_pwm");
-	if (ret) {
-		pr_err("%s: Request reset gpio_panel_pwm failed, ret=%d\n",
-				__func__, ret);
-		goto edp_free_pwm;
 	}
 
 	return 0;
-
-edp_free_pwm:
-	pwm_free(edp_drv->bl_pwm);
-	return -ENODEV;
 }
 
 void mdss_edp_set_backlight(struct mdss_panel_data *pdata, u32 bl_level)
@@ -218,27 +205,26 @@
 		return;
 	}
 
-	bl_max = edp_drv->panel_data.panel_info.bl_max;
-	if (bl_level > bl_max)
-		bl_level = bl_max;
+	if (edp_drv->bl_pwm != NULL) {
+		bl_max = edp_drv->panel_data.panel_info.bl_max;
+		if (bl_level > bl_max)
+			bl_level = bl_max;
 
-	if (edp_drv->bl_pwm == NULL) {
-		pr_err("%s: edp_drv->bl_pwm=NULL.\n", __func__);
-		return;
-	}
+		ret = pwm_config(edp_drv->bl_pwm,
+				bl_level * edp_drv->pwm_period / bl_max,
+				edp_drv->pwm_period);
+		if (ret) {
+			pr_err("%s: pwm_config() failed err=%d.\n", __func__,
+					ret);
+			return;
+		}
 
-	ret = pwm_config(edp_drv->bl_pwm,
-			bl_level * edp_drv->pwm_period / bl_max,
-			edp_drv->pwm_period);
-	if (ret) {
-		pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
-		return;
-	}
-
-	ret = pwm_enable(edp_drv->bl_pwm);
-	if (ret) {
-		pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
-		return;
+		ret = pwm_enable(edp_drv->bl_pwm);
+		if (ret) {
+			pr_err("%s: pwm_enable() failed err=%d\n", __func__,
+					ret);
+			return;
+		}
 	}
 }
 
@@ -378,7 +364,8 @@
 	mdss_edp_irq_disable(edp_drv);
 
 	gpio_set_value(edp_drv->gpio_panel_en, 0);
-	pwm_disable(edp_drv->bl_pwm);
+	if (edp_drv->bl_pwm != NULL)
+		pwm_disable(edp_drv->bl_pwm);
 	mdss_edp_enable(edp_drv->base, 0);
 	mdss_edp_unconfig_clk(edp_drv->base, edp_drv->mmss_cc_base);
 	mdss_edp_enable_mainlink(edp_drv->base, 0);
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index c3f7d0d..33b899f 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.h
@@ -261,7 +261,6 @@
 
 	/* gpios */
 	int gpio_panel_en;
-	int gpio_panel_pwm;
 
 	/* backlight */
 	struct pwm_device *bl_pwm;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4ca0a3f..105dd1a 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -43,6 +43,7 @@
 #include <linux/sw_sync.h>
 #include <linux/file.h>
 #include <linux/memory_alloc.h>
+#include <linux/kthread.h>
 
 #include <mach/board.h>
 #include <mach/memory.h>
@@ -74,6 +75,7 @@
 static int mdss_fb_register(struct msm_fb_data_type *mfd);
 static int mdss_fb_open(struct fb_info *info, int user);
 static int mdss_fb_release(struct fb_info *info, int user);
+static int mdss_fb_release_all(struct fb_info *info, bool release_all);
 static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
 			       struct fb_info *info);
 static int mdss_fb_check_var(struct fb_var_screeninfo *var,
@@ -86,8 +88,10 @@
 			 unsigned long arg);
 static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 static void mdss_fb_release_fences(struct msm_fb_data_type *mfd);
+static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
+		unsigned long val, void *data);
 
-static void mdss_fb_commit_wq_handler(struct work_struct *work);
+static int __mdss_fb_display_thread(void *data);
 static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
 static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
 					int event, void *arg);
@@ -290,10 +294,9 @@
 {
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
-	for (; mfd->ref_cnt > 1; mfd->ref_cnt--)
-		pm_runtime_put(mfd->fbi->dev);
-
-	mdss_fb_release(mfd->fbi, 0);
+	lock_fb_info(mfd->fbi);
+	mdss_fb_release_all(mfd->fbi, true);
+	unlock_fb_info(mfd->fbi);
 }
 
 static int mdss_fb_probe(struct platform_device *pdev)
@@ -386,11 +389,12 @@
 		if (mfd->mdp_sync_pt_data.timeline == NULL) {
 			pr_err("%s: cannot create time line", __func__);
 			return -ENOMEM;
-		} else {
-			mfd->mdp_sync_pt_data.timeline_value = 0;
 		}
+		mfd->mdp_sync_pt_data.notifier.notifier_call =
+			__mdss_fb_sync_buf_done_callback;
 	}
-	if (mfd->panel.type == WRITEBACK_PANEL)
+	if ((mfd->panel.type == WRITEBACK_PANEL) ||
+			(mfd->panel.type == MIPI_CMD_PANEL))
 		mfd->mdp_sync_pt_data.threshold = 1;
 	else
 		mfd->mdp_sync_pt_data.threshold = 2;
@@ -1086,6 +1090,8 @@
 	mutex_init(&mfd->update.lock);
 	mutex_init(&mfd->no_update.lock);
 	mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);
+	atomic_set(&mfd->mdp_sync_pt_data.commit_cnt, 0);
+	atomic_set(&mfd->commits_pending, 0);
 
 	init_timer(&mfd->no_update.timer);
 	mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
@@ -1093,15 +1099,9 @@
 	init_completion(&mfd->update.comp);
 	init_completion(&mfd->no_update.comp);
 	init_completion(&mfd->power_off_comp);
-	init_completion(&mfd->commit_comp);
 	init_completion(&mfd->power_set_comp);
-	INIT_WORK(&mfd->commit_work, mdss_fb_commit_wq_handler);
-	mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type),
-		GFP_KERNEL);
-	if (mfd->msm_fb_backup == 0) {
-		pr_err("error: not enough memory!\n");
-		return -ENOMEM;
-	}
+	init_waitqueue_head(&mfd->commit_wait_q);
+	init_waitqueue_head(&mfd->idle_wait_q);
 
 	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 	if (ret)
@@ -1118,9 +1118,9 @@
 		     mfd->index, fbi->var.xres, fbi->var.yres,
 		     fbi->fix.smem_len);
 
-	ret = 0;
+	kthread_run(__mdss_fb_display_thread, mfd, "mdss_fb%d", mfd->index);
 
-	return ret;
+	return 0;
 }
 
 static int mdss_fb_open(struct fb_info *info, int user)
@@ -1168,10 +1168,10 @@
 	return 0;
 }
 
-static int mdss_fb_release(struct fb_info *info, int user)
+static int mdss_fb_release_all(struct fb_info *info, bool release_all)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	struct mdss_fb_proc_info *pinfo = NULL;
+	struct mdss_fb_proc_info *pinfo = NULL, *temp_pinfo = NULL;
 	int ret = 0;
 	int pid = current->tgid;
 
@@ -1181,27 +1181,26 @@
 	}
 
 	mdss_fb_pan_idle(mfd);
-	mfd->ref_cnt--;
 
-	list_for_each_entry(pinfo, &mfd->proc_list, list) {
-		if (pinfo->pid == pid)
-			break;
-	}
+	pr_debug("release_all = %s\n", release_all ? "true" : "false");
 
-	if (!pinfo || (pinfo->pid != pid)) {
-		pr_warn("unable to find process info for fb%d pid=%d\n",
-				mfd->index, pid);
-		if (mfd->mdp.release_fnc) {
-			ret = mfd->mdp.release_fnc(mfd);
-			if (ret)
-				pr_err("error releasing fb%d resources\n",
-						mfd->index);
-		}
-	} else {
-		pr_debug("found process entry pid=%d ref=%d\n",
-				pinfo->pid, pinfo->ref_cnt);
+	list_for_each_entry_safe(pinfo, temp_pinfo, &mfd->proc_list, list) {
+		if (!release_all && (pinfo->pid != pid))
+			continue;
 
-		pinfo->ref_cnt--;
+		pr_debug("found process entry pid=%d ref=%d\n", pinfo->pid,
+			pinfo->ref_cnt);
+
+		do {
+			if (mfd->ref_cnt < pinfo->ref_cnt)
+				pr_warn("WARN:mfd->ref_cnt < pinfo->ref_cnt\n");
+			else
+				mfd->ref_cnt--;
+
+			pinfo->ref_cnt--;
+			pm_runtime_put(info->dev);
+		} while (release_all && pinfo->ref_cnt);
+
 		if (pinfo->ref_cnt == 0) {
 			if (mfd->mdp.release_fnc) {
 				ret = mfd->mdp.release_fnc(mfd);
@@ -1216,17 +1215,22 @@
 
 	if (!mfd->ref_cnt) {
 		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
-				       mfd->op_enable);
+			mfd->op_enable);
 		if (ret) {
-			pr_err("can't turn off fb%d! rc=%d\n", mfd->index, ret);
+			pr_err("can't turn off fb%d! rc=%d\n",
+				mfd->index, ret);
 			return ret;
 		}
 	}
 
-	pm_runtime_put(info->dev);
 	return ret;
 }
 
+static int mdss_fb_release(struct fb_info *info, int user)
+{
+	return mdss_fb_release_all(info, false);
+}
+
 static void mdss_fb_power_setting_idle(struct msm_fb_data_type *mfd)
 {
 	int ret;
@@ -1249,85 +1253,155 @@
 
 void mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
 {
+	struct sync_fence *fences[MDP_MAX_FENCE_FD];
+	int fence_cnt;
 	int i, ret = 0;
+
+	pr_debug("%s: wait for fences\n", sync_pt_data->fence_name);
+
+	mutex_lock(&sync_pt_data->sync_mutex);
+	/*
+	 * Assuming that acq_fen_cnt is sanitized in bufsync ioctl
+	 * to check for sync_pt_data->acq_fen_cnt) <= MDP_MAX_FENCE_FD
+	 */
+	fence_cnt = sync_pt_data->acq_fen_cnt;
+	sync_pt_data->acq_fen_cnt = 0;
+	if (fence_cnt)
+		memcpy(fences, sync_pt_data->acq_fen,
+				fence_cnt * sizeof(struct sync_fence *));
+	mutex_unlock(&sync_pt_data->sync_mutex);
+
 	/* buf sync */
-	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++) {
-		ret = sync_fence_wait(sync_pt_data->acq_fen[i],
+	for (i = 0; i < fence_cnt && !ret; i++) {
+		ret = sync_fence_wait(fences[i],
 				WAIT_FENCE_FIRST_TIMEOUT);
 		if (ret == -ETIME) {
-			pr_warn("sync_fence_wait timed out! ");
+			pr_warn("%s: sync_fence_wait timed out! ",
+					sync_pt_data->fence_name);
 			pr_cont("Waiting %ld more seconds\n",
 					WAIT_FENCE_FINAL_TIMEOUT/MSEC_PER_SEC);
-			ret = sync_fence_wait(sync_pt_data->acq_fen[i],
+			ret = sync_fence_wait(fences[i],
 					WAIT_FENCE_FINAL_TIMEOUT);
 		}
-		if (ret < 0) {
-			pr_err("%s: sync_fence_wait failed! ret = %x\n",
-				__func__, ret);
-			break;
-		}
-		sync_fence_put(sync_pt_data->acq_fen[i]);
+		sync_fence_put(fences[i]);
 	}
 
 	if (ret < 0) {
-		while (i < sync_pt_data->acq_fen_cnt) {
-			sync_fence_put(sync_pt_data->acq_fen[i]);
-			i++;
-		}
+		pr_err("%s: sync_fence_wait failed! ret = %x\n",
+				sync_pt_data->fence_name, ret);
+		for (; i < fence_cnt; i++)
+			sync_fence_put(fences[i]);
 	}
-	sync_pt_data->acq_fen_cnt = 0;
 }
 
-static void mdss_fb_signal_timeline_locked(
-				struct msm_sync_pt_data *sync_pt_data)
-{
-	if (sync_pt_data->timeline && !list_empty((const struct list_head *)
-			(&(sync_pt_data->timeline->obj.active_list_head)))) {
-		sw_sync_timeline_inc(sync_pt_data->timeline, 1);
-		sync_pt_data->timeline_value++;
-	}
-	sync_pt_data->cur_rel_fence = 0;
-}
-
+/**
+ * mdss_fb_signal_timeline() - signal a single release fence
+ * @sync_pt_data:	Sync point data structure for the timeline which
+ *			should be signaled.
+ *
+ * This is called after a frame has been pushed to display. This signals the
+ * timeline to release the fences associated with this frame.
+ */
 void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data)
 {
 	mutex_lock(&sync_pt_data->sync_mutex);
-	mdss_fb_signal_timeline_locked(sync_pt_data);
+	if (atomic_add_unless(&sync_pt_data->commit_cnt, -1, 0) &&
+			sync_pt_data->timeline) {
+		sw_sync_timeline_inc(sync_pt_data->timeline, 1);
+		sync_pt_data->timeline_value++;
+
+		pr_debug("%s: buffer signaled! timeline val=%d remaining=%d\n",
+			sync_pt_data->fence_name, sync_pt_data->timeline_value,
+			atomic_read(&sync_pt_data->commit_cnt));
+	} else {
+		pr_debug("%s timeline signaled without commits val=%d\n",
+			sync_pt_data->fence_name, sync_pt_data->timeline_value);
+	}
 	mutex_unlock(&sync_pt_data->sync_mutex);
 }
 
+/**
+ * mdss_fb_release_fences() - signal all pending release fences
+ * @mfd:	Framebuffer data structure for display
+ *
+ * Release all currently pending release fences, including those that are in
+ * the process to be commited.
+ *
+ * Note: this should only be called during close or suspend sequence.
+ */
 static void mdss_fb_release_fences(struct msm_fb_data_type *mfd)
 {
+	struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
+	int val;
 
-	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
-	if (mfd->mdp_sync_pt_data.timeline) {
-		sw_sync_timeline_inc(mfd->mdp_sync_pt_data.timeline, 2);
-		mfd->mdp_sync_pt_data.timeline_value += 2;
+	mutex_lock(&sync_pt_data->sync_mutex);
+	if (sync_pt_data->timeline) {
+		val = sync_pt_data->threshold +
+			atomic_read(&sync_pt_data->commit_cnt);
+		sw_sync_timeline_inc(sync_pt_data->timeline, val);
+		sync_pt_data->timeline_value += val;
+		atomic_set(&sync_pt_data->commit_cnt, 0);
 	}
-	mfd->mdp_sync_pt_data.cur_rel_fence = 0;
-	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
+	mutex_unlock(&sync_pt_data->sync_mutex);
 }
 
+/**
+ * __mdss_fb_sync_buf_done_callback() - process async display events
+ * @p:		Notifier block registered for async events.
+ * @event:	Event enum to identify the event.
+ * @data:	Optional argument provided with the event.
+ *
+ * See enum mdp_notify_event for events handled.
+ */
+static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
+		unsigned long event, void *data)
+{
+	struct msm_sync_pt_data *sync_pt_data;
+
+	sync_pt_data = container_of(p, struct msm_sync_pt_data, notifier);
+
+	switch (event) {
+	case MDP_NOTIFY_FRAME_READY:
+		if (sync_pt_data->async_wait_fences)
+			mdss_fb_wait_for_fence(sync_pt_data);
+		break;
+	case MDP_NOTIFY_FRAME_FLUSHED:
+		pr_debug("%s: frame flushed\n", sync_pt_data->fence_name);
+		sync_pt_data->flushed = true;
+		break;
+	case MDP_NOTIFY_FRAME_TIMEOUT:
+		pr_err("%s: frame timeout\n", sync_pt_data->fence_name);
+		mdss_fb_signal_timeline(sync_pt_data);
+		break;
+	case MDP_NOTIFY_FRAME_DONE:
+		pr_debug("%s: frame done\n", sync_pt_data->fence_name);
+		mdss_fb_signal_timeline(sync_pt_data);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+/**
+ * mdss_fb_pan_idle() - wait for panel programming to be idle
+ * @mfd:	Framebuffer data structure for display
+ *
+ * Wait for any pending programming to be done if in the process of programming
+ * hardware configuration. After this function returns it is safe to perform
+ * software updates for next frame.
+ */
 static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
 {
 	int ret;
 
-	if (mfd->is_committing) {
-		ret = wait_for_completion_timeout(
-				&mfd->commit_comp,
+	ret = wait_event_timeout(mfd->idle_wait_q,
+			!atomic_read(&mfd->commits_pending),
 			msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
-		if (ret < 0)
-			ret = -ERESTARTSYS;
-		else if (!ret)
-			pr_err("%s wait for commit_comp timeout %d %d",
-				__func__, ret, mfd->is_committing);
-		if (ret <= 0) {
-			mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
-			mdss_fb_signal_timeline_locked(&mfd->mdp_sync_pt_data);
-			mfd->is_committing = 0;
-			complete_all(&mfd->commit_comp);
-			mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
-		}
+	if (!ret) {
+		pr_err("wait for idle timeout %d pending=%d\n",
+				ret, atomic_read(&mfd->commits_pending));
+
+		mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
 	}
 }
 
@@ -1335,7 +1409,6 @@
 		struct mdp_display_commit *disp_commit)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	struct msm_fb_backup_type *fb_backup;
 	struct fb_var_screeninfo *var = &disp_commit->var;
 	u32 wait_for_finish = disp_commit->wait_for_finish;
 	int ret = 0;
@@ -1360,13 +1433,12 @@
 		info->var.yoffset =
 		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
 
-	fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
-	memcpy(&fb_backup->info, info, sizeof(struct fb_info));
-	memcpy(&fb_backup->disp_commit, disp_commit,
-		sizeof(struct mdp_display_commit));
-	INIT_COMPLETION(mfd->commit_comp);
-	mfd->is_committing = 1;
-	schedule_work(&mfd->commit_work);
+	mfd->msm_fb_backup.info = *info;
+	mfd->msm_fb_backup.disp_commit = *disp_commit;
+
+	atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
+	atomic_inc(&mfd->commits_pending);
+	wake_up_all(&mfd->commit_wait_q);
 	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (wait_for_finish)
 		mdss_fb_pan_idle(mfd);
@@ -1405,14 +1477,12 @@
 		info->var.yoffset =
 		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
 
-	mdss_fb_wait_for_fence(&mfd->mdp_sync_pt_data);
 	if (mfd->mdp.dma_fnc)
 		mfd->mdp.dma_fnc(mfd);
 	else
 		pr_warn("dma function not set for panel type=%d\n",
 				mfd->panel.type);
-	mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
-	mdss_fb_update_backlight(mfd);
+
 	return 0;
 }
 
@@ -1430,35 +1500,69 @@
 	pinfo->clk_rate = var->pixclock;
 }
 
-static void mdss_fb_commit_wq_handler(struct work_struct *work)
+/**
+ * __mdss_fb_perform_commit() - process a frame to display
+ * @mfd:	Framebuffer data structure for display
+ *
+ * Processes all layers and buffers programmed and ensures all pending release
+ * fences are signaled once the buffer is transfered to display.
+ */
+static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd)
 {
-	struct msm_fb_data_type *mfd;
-	struct fb_var_screeninfo *var;
-	struct fb_info *info;
-	struct msm_fb_backup_type *fb_backup;
-	int ret = 0;
+	struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
+	struct msm_fb_backup_type *fb_backup = &mfd->msm_fb_backup;
+	int ret = -ENOSYS;
 
-	mfd = container_of(work, struct msm_fb_data_type, commit_work);
-	fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
-	info = &fb_backup->info;
-	if (fb_backup->disp_commit.flags &
-		MDP_DISPLAY_COMMIT_OVERLAY) {
-		mdss_fb_wait_for_fence(&mfd->mdp_sync_pt_data);
+	if (!sync_pt_data->async_wait_fences)
+		mdss_fb_wait_for_fence(sync_pt_data);
+	sync_pt_data->flushed = false;
+
+	if (fb_backup->disp_commit.flags & MDP_DISPLAY_COMMIT_OVERLAY) {
 		if (mfd->mdp.kickoff_fnc)
-			ret = mfd->mdp.kickoff_fnc(mfd, &fb_backup->disp_commit);
-		if (!ret)
-			mdss_fb_update_backlight(mfd);
-		mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
+			ret = mfd->mdp.kickoff_fnc(mfd,
+					&fb_backup->disp_commit);
+		else
+			pr_warn("no kickoff function setup for fb%d\n",
+					mfd->index);
 	} else {
-		var = &fb_backup->disp_commit.var;
-		ret = mdss_fb_pan_display_sub(var, info);
+		ret = mdss_fb_pan_display_sub(&fb_backup->disp_commit.var,
+				&fb_backup->info);
 		if (ret)
-			pr_err("%s fails: ret = %x", __func__, ret);
+			pr_err("pan display failed %x on fb%d\n", ret,
+					mfd->index);
 	}
-	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
-	mfd->is_committing = 0;
-	complete_all(&mfd->commit_comp);
-	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
+	if (!ret)
+		mdss_fb_update_backlight(mfd);
+
+	if (IS_ERR_VALUE(ret) || !sync_pt_data->flushed)
+		mdss_fb_signal_timeline(sync_pt_data);
+
+	return ret;
+}
+
+static int __mdss_fb_display_thread(void *data)
+{
+	struct msm_fb_data_type *mfd = data;
+	int ret;
+	struct sched_param param;
+
+	param.sched_priority = 16;
+	ret = sched_setscheduler(current, SCHED_FIFO, &param);
+	if (ret)
+		pr_warn("set priority failed for fb%d display thread\n",
+				mfd->index);
+
+	while (1) {
+		wait_event(mfd->commit_wait_q,
+				atomic_read(&mfd->commits_pending));
+
+		ret = __mdss_fb_perform_commit(mfd);
+
+		atomic_dec(&mfd->commits_pending);
+		wake_up_all(&mfd->idle_wait_q);
+	}
+
+	return ret;
 }
 
 static int mdss_fb_check_var(struct fb_var_screeninfo *var,
@@ -1716,12 +1820,52 @@
 	return 0;
 }
 
+/**
+ * mdss_fb_sync_get_rel_fence() - get release fence from sync pt timeline
+ * @sync_pt_data:	Sync pt structure holding timeline and fence info.
+ *
+ * Function returns a release fence on the timeline associated with the
+ * sync pt struct given and it's associated information. The release fence
+ * created can be used to signal when buffers provided will be released.
+ */
+static struct sync_fence *__mdss_fb_sync_get_rel_fence(
+		struct msm_sync_pt_data *sync_pt_data)
+{
+	struct sync_pt *rel_sync_pt;
+	struct sync_fence *rel_fence;
+	int val;
+
+	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
+		atomic_read(&sync_pt_data->commit_cnt);
+
+	pr_debug("%s: buf sync rel fence timeline=%d\n",
+		sync_pt_data->fence_name, val);
+
+	rel_sync_pt = sw_sync_pt_create(sync_pt_data->timeline, val);
+	if (rel_sync_pt == NULL) {
+		pr_err("%s: cannot create sync point\n",
+				sync_pt_data->fence_name);
+		return NULL;
+	}
+
+	/* create fence */
+	rel_fence = sync_fence_create(sync_pt_data->fence_name, rel_sync_pt);
+	if (rel_fence == NULL) {
+		sync_pt_free(rel_sync_pt);
+		pr_err("%s: cannot create fence\n", sync_pt_data->fence_name);
+		return NULL;
+	}
+
+	return rel_fence;
+}
+
 static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
 				 struct mdp_buf_sync *buf_sync)
 {
 	int i, ret = 0;
 	int acq_fen_fd[MDP_MAX_FENCE_FD];
-	struct sync_fence *fence;
+	struct sync_fence *fence, *rel_fence;
+	int rel_fen_fd;
 
 	if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
 				(sync_pt_data->timeline == NULL))
@@ -1731,16 +1875,24 @@
 		ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
 				buf_sync->acq_fen_fd_cnt * sizeof(int));
 	if (ret) {
-		pr_err("%s:copy_from_user failed", __func__);
+		pr_err("%s: copy_from_user failed", sync_pt_data->fence_name);
 		return ret;
 	}
 
+	if (sync_pt_data->acq_fen_cnt) {
+		pr_warn("%s: currently %d fences active. waiting...\n",
+				sync_pt_data->fence_name,
+				sync_pt_data->acq_fen_cnt);
+		mdss_fb_wait_for_fence(sync_pt_data);
+	}
+
 	mutex_lock(&sync_pt_data->sync_mutex);
 	for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
 		fence = sync_fence_fdget(acq_fen_fd[i]);
 		if (fence == NULL) {
-			pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
-				acq_fen_fd[i]);
+			pr_err("%s: null fence! i=%d fd=%d\n",
+					sync_pt_data->fence_name, i,
+					acq_fen_fd[i]);
 			ret = -EINVAL;
 			break;
 		}
@@ -1750,54 +1902,40 @@
 	if (ret)
 		goto buf_sync_err_1;
 
-	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
-		mdss_fb_wait_for_fence(sync_pt_data);
-
-	sync_pt_data->cur_rel_sync_pt = sw_sync_pt_create(
-			sync_pt_data->timeline, sync_pt_data->timeline_value +
-					sync_pt_data->threshold);
-
-	if (sync_pt_data->cur_rel_sync_pt == NULL) {
-		pr_err("%s: cannot create sync point", __func__);
-		ret = -ENOMEM;
+	rel_fence = __mdss_fb_sync_get_rel_fence(sync_pt_data);
+	if (IS_ERR_OR_NULL(rel_fence)) {
+		pr_err("%s: unable to retrieve release fence\n",
+				sync_pt_data->fence_name);
+		ret = rel_fence ? PTR_ERR(rel_fence) : -ENOMEM;
 		goto buf_sync_err_1;
 	}
-	/* create fence */
-	sync_pt_data->cur_rel_fence = sync_fence_create(
-		sync_pt_data->fence_name, sync_pt_data->cur_rel_sync_pt);
 
-	if (sync_pt_data->cur_rel_fence == NULL) {
-		sync_pt_free(sync_pt_data->cur_rel_sync_pt);
-		sync_pt_data->cur_rel_sync_pt = NULL;
-		pr_err("%s: cannot create fence", __func__);
-		ret = -ENOMEM;
-		goto buf_sync_err_1;
-	}
 	/* create fd */
-	sync_pt_data->cur_rel_fen_fd = get_unused_fd_flags(0);
-	if (sync_pt_data->cur_rel_fen_fd < 0) {
-		pr_err("%s: get_unused_fd_flags failed", __func__);
-		ret  = -EIO;
+	rel_fen_fd = get_unused_fd_flags(0);
+	if (rel_fen_fd < 0) {
+		pr_err("%s: get_unused_fd_flags failed\n",
+				sync_pt_data->fence_name);
+		ret = -EIO;
 		goto buf_sync_err_2;
 	}
 
-	sync_fence_install(sync_pt_data->cur_rel_fence,
-					sync_pt_data->cur_rel_fen_fd);
-	ret = copy_to_user(buf_sync->rel_fen_fd,
-				&sync_pt_data->cur_rel_fen_fd, sizeof(int));
+	sync_fence_install(rel_fence, rel_fen_fd);
 
+	ret = copy_to_user(buf_sync->rel_fen_fd, &rel_fen_fd, sizeof(int));
 	if (ret) {
-		pr_err("%s:copy_to_user failed", __func__);
+		pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name);
 		goto buf_sync_err_3;
 	}
 	mutex_unlock(&sync_pt_data->sync_mutex);
+
+	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+		mdss_fb_wait_for_fence(sync_pt_data);
+
 	return ret;
 buf_sync_err_3:
-	put_unused_fd(sync_pt_data->cur_rel_fen_fd);
+	put_unused_fd(rel_fen_fd);
 buf_sync_err_2:
-	sync_fence_put(sync_pt_data->cur_rel_fence);
-	sync_pt_data->cur_rel_fence = NULL;
-	sync_pt_data->cur_rel_fen_fd = 0;
+	sync_fence_put(rel_fence);
 buf_sync_err_1:
 	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
 		sync_fence_put(sync_pt_data->acq_fen[i]);
@@ -1834,8 +1972,8 @@
 		return -EINVAL;
 	mfd = (struct msm_fb_data_type *)info->par;
 	mdss_fb_power_setting_idle(mfd);
-
-	mdss_fb_pan_idle(mfd);
+	if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL))
+		mdss_fb_pan_idle(mfd);
 
 	switch (cmd) {
 	case MSMFB_CURSOR:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 256789d..8213dbe 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/msm_mdp.h>
 #include <linux/types.h>
+#include <linux/notifier.h>
 
 #include "mdss_panel.h"
 
@@ -40,6 +41,32 @@
 #define  MIN(x, y) (((x) < (y)) ? (x) : (y))
 #endif
 
+/**
+ * enum mdp_notify_event - Different frame events to indicate frame update state
+ *
+ * @MDP_NOTIFY_FRAME_BEGIN:	Frame update has started, the frame is about to
+ *				be programmed into hardware.
+ * @MDP_NOTIFY_FRAME_READY:	Frame ready to be kicked off, this can be used
+ *				as the last point in time to synchronized with
+ *				source buffers before kickoff.
+ * @MDP_NOTIFY_FRAME_FLUSHED:	Configuration of frame has been flushed and
+ *				DMA transfer has started.
+ * @MDP_NOTIFY_FRAME_DONE:	Frame DMA transfer has completed.
+ *				- For video mode panels this will indicate that
+ *				  previous frame has been replaced by new one.
+ *				- For command mode/writeback frame done happens
+ *				  as soon as the DMA of the frame is done.
+ * @MDP_NOTIFY_FRAME_TIMEOUT:	Frame DMA transfer has failed to complete within
+ *				a fair amount of time.
+ */
+enum mdp_notify_event {
+	MDP_NOTIFY_FRAME_BEGIN = 1,
+	MDP_NOTIFY_FRAME_READY,
+	MDP_NOTIFY_FRAME_FLUSHED,
+	MDP_NOTIFY_FRAME_DONE,
+	MDP_NOTIFY_FRAME_TIMEOUT,
+};
+
 struct disp_info_type_suspend {
 	int op_enable;
 	int panel_power_on;
@@ -57,13 +84,17 @@
 	char *fence_name;
 	u32 acq_fen_cnt;
 	struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
-	int cur_rel_fen_fd;
-	struct sync_pt *cur_rel_sync_pt;
-	struct sync_fence *cur_rel_fence;
+
 	struct sw_sync_timeline *timeline;
 	int timeline_value;
 	u32 threshold;
+
+	atomic_t commit_cnt;
+	bool flushed;
+	bool async_wait_fences;
+
 	struct mutex sync_mutex;
+	struct notifier_block notifier;
 };
 
 struct msm_fb_data_type;
@@ -105,6 +136,11 @@
 	struct list_head list;
 };
 
+struct msm_fb_backup_type {
+	struct fb_info info;
+	struct mdp_display_commit disp_commit;
+};
+
 struct msm_fb_data_type {
 	u32 key;
 	u32 index;
@@ -159,10 +195,11 @@
 	struct msm_sync_pt_data mdp_sync_pt_data;
 
 	/* for non-blocking */
-	struct completion commit_comp;
-	u32 is_committing;
-	struct work_struct commit_work;
-	void *msm_fb_backup;
+	atomic_t commits_pending;
+	wait_queue_head_t commit_wait_q;
+	wait_queue_head_t idle_wait_q;
+
+	struct msm_fb_backup_type msm_fb_backup;
 	struct completion power_set_comp;
 	u32 is_power_setting;
 
@@ -170,11 +207,6 @@
 	struct list_head proc_list;
 };
 
-struct msm_fb_backup_type {
-	struct fb_info info;
-	struct mdp_display_commit disp_commit;
-};
-
 static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
 {
 	int needs_complete = 0;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index b000e2f..cf0c287 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -29,6 +29,9 @@
 
 #define BUFF_SIZE_3D 128
 
+/* Support for first 5 EDID blocks */
+#define MAX_EDID_BLOCK_SIZE (0x80 * 5)
+
 struct hdmi_edid_sink_data {
 	u32 disp_mode_list[HDMI_VFRMT_MAX];
 	u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -52,6 +55,7 @@
 	int adb_size;
 	u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
 	int sadb_size;
+	u8 edid_buf[MAX_EDID_BLOCK_SIZE];
 
 	struct hdmi_edid_sink_data sink_data;
 	struct hdmi_edid_init_data init_data;
@@ -352,11 +356,30 @@
 } /* hdmi_edid_sysfs_rda_3d_modes */
 static DEVICE_ATTR(edid_3d_modes, S_IRUGO, hdmi_edid_sysfs_rda_3d_modes, NULL);
 
+static ssize_t hdmi_common_rda_edid_raw_data(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(buf, edid_ctrl->edid_buf,
+		sizeof(edid_ctrl->edid_buf));
+
+	return sizeof(edid_ctrl->edid_buf);
+} /* hdmi_common_rda_edid_raw_data */
+static DEVICE_ATTR(edid_raw_data, S_IRUGO, hdmi_common_rda_edid_raw_data, NULL);
+
 static struct attribute *hdmi_edid_fs_attrs[] = {
 	&dev_attr_edid_modes.attr,
 	&dev_attr_pa.attr,
 	&dev_attr_scan_info.attr,
 	&dev_attr_edid_3d_modes.attr,
+	&dev_attr_edid_raw_data.attr,
 	NULL,
 };
 
@@ -446,13 +469,17 @@
 	return status;
 } /* hdmi_edid_read_block */
 
+#define EDID_BLK_LEN 128
+#define EDID_DTD_LEN 18
 static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
 	u8 type, u8 *len)
 {
 	/* the start of data block collection, start of Video Data Block */
 	u32 offset = start_offset;
-	u32 end_dbc_offset = in_buf[2];
+	u32 dbc_offset = in_buf[2];
 
+	if (dbc_offset >= EDID_BLK_LEN - EDID_DTD_LEN)
+		return NULL;
 	*len = 0;
 
 	/*
@@ -461,14 +488,15 @@
 	 * * edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block
 	 *   collection present and no DTD data present.
 	 */
-	if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) {
+	if ((dbc_offset == 0) || (dbc_offset == 4)) {
 		DEV_WARN("EDID: no DTD or non-DTD data present\n");
 		return NULL;
 	}
 
-	while (offset < end_dbc_offset) {
+	while (offset < dbc_offset) {
 		u8 block_len = in_buf[offset] & 0x1F;
-		if ((in_buf[offset] >> 5) == type) {
+		if ((offset + block_len <= dbc_offset) &&
+		    (in_buf[offset] >> 5) == type) {
 			*len = block_len;
 			DEV_DBG("%s: EDID: block=%d found @ 0x%x w/ len=%d\n",
 				__func__, type, offset, block_len);
@@ -672,7 +700,7 @@
 	}
 
 	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
-	if (vsd == NULL)
+	if (vsd == NULL || len < 8)
 		return 0;
 
 	DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
@@ -862,7 +890,7 @@
 	}
 } /* hdmi_edid_add_sink_video_format */
 
-static void hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf,
+static int hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf,
 	struct hdmi_edid_sink_data *sink_data, u32 num_of_cea_blocks)
 {
 	u8 len, offset, present_multi_3d, hdmi_vic_len;
@@ -873,22 +901,34 @@
 				3, &len) : NULL;
 	int i;
 
+	if (!vsd)
+		return -ENXIO;
+
 	offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+	if (offset >= len - 1)
+		return -ETOOSMALL;
+
 	present_multi_3d = (vsd[offset] & 0x60) >> 5;
 
 	offset += 1;
+
 	hdmi_vic_len = (vsd[offset] >> 5) & 0x7;
 	hdmi_3d_len = vsd[offset] & 0x1F;
 	DEV_DBG("%s: EDID[3D]: HDMI_VIC_LEN = %d, HDMI_3D_LEN = %d\n", __func__,
 		hdmi_vic_len, hdmi_3d_len);
 
 	offset += (hdmi_vic_len + 1);
+	if (offset >= len - 1)
+		return -ETOOSMALL;
+
 	if (present_multi_3d == 1 || present_multi_3d == 2) {
 		DEV_DBG("%s: EDID[3D]: multi 3D present (%d)\n", __func__,
 			present_multi_3d);
 		/* 3d_structure_all */
 		structure_all = (vsd[offset] << 8) | vsd[offset + 1];
 		offset += 2;
+		if (offset >= len - 1)
+			return -ETOOSMALL;
 		hdmi_3d_len -= 2;
 		if (present_multi_3d == 2) {
 			/* 3d_structure_mask */
@@ -935,16 +975,18 @@
 
 	i = 0;
 	while (hdmi_3d_len > 0) {
+		if (offset >= len - 1)
+			return -ETOOSMALL;
 		DEV_DBG("%s: EDID: 3D_Structure_%d @ 0x%x: %02x\n",
 			__func__, i + 1, offset, vsd[offset]);
-
 		if ((vsd[offset] >> 4) >=
 			sink_data->disp_multi_3d_mode_list_cnt) {
 			if ((vsd[offset] & 0x0F) >= 8) {
 				offset += 1;
 				hdmi_3d_len -= 1;
 				DEV_DBG("%s:EDID:3D_Detail_%d @ 0x%x: %02x\n",
-					__func__, i + 1, offset, vsd[offset]);
+					__func__, i + 1, offset,
+					vsd[min_t(u32, offset, (len - 1))]);
 			}
 			i += 1;
 			offset += 1;
@@ -980,12 +1022,13 @@
 			hdmi_3d_len -= 1;
 			DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ 0x%x: %02x\n",
 				__func__, i + 1, offset,
-				vsd[offset]);
+				vsd[min_t(u32, offset, (len - 1))]);
 		}
 		i += 1;
 		offset += 1;
 		hdmi_3d_len -= 1;
 	}
+	return 0;
 } /* hdmi_edid_get_display_vsd_3d_mode */
 
 static void hdmi_edid_get_extended_video_formats(
@@ -1038,6 +1081,7 @@
 	u32 video_format = HDMI_VFRMT_640x480p60_4_3;
 	u32 has480p = false;
 	u8 len;
+	int rc;
 	const u8 *edid_blk0 = NULL;
 	const u8 *edid_blk1 = NULL;
 	const u8 *svd = NULL;
@@ -1288,8 +1332,10 @@
 		}
 
 		/* 3d format described in Vendor Specific Data */
-		hdmi_edid_get_display_vsd_3d_mode(data_buf, sink_data,
+		rc = hdmi_edid_get_display_vsd_3d_mode(data_buf, sink_data,
 			num_of_cea_blocks);
+		if (!rc)
+			pr_debug("%s: 3D formats in VSD\n", __func__);
 	}
 
 	/*
@@ -1305,7 +1351,7 @@
 int hdmi_edid_read(void *input)
 {
 	/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
-	u8 edid_buf[0x80 * 4];
+	u8 *edid_buf = NULL;
 	u32 cea_extension_ver = 0;
 	u32 num_of_cea_blocks = 0;
 	u32 ieee_reg_id = 0;
@@ -1319,12 +1365,14 @@
 		return -EINVAL;
 	}
 
+	edid_buf = edid_ctrl->edid_buf;
+
 	edid_ctrl->pt_scan_info = 0;
 	edid_ctrl->it_scan_info = 0;
 	edid_ctrl->ce_scan_info = 0;
 	edid_ctrl->present_3d = 0;
 	memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
-	memset(edid_buf, 0, sizeof(edid_buf));
+	memset(edid_buf, 0, sizeof(edid_ctrl->edid_buf));
 	memset(edid_ctrl->audio_data_block, 0,
 		sizeof(edid_ctrl->audio_data_block));
 	memset(edid_ctrl->spkr_alloc_data_block, 0,
@@ -1391,7 +1439,7 @@
 		for (i = 1; i <= num_of_cea_blocks; i++) {
 			if (!(i % 2)) {
 				status = hdmi_edid_read_block(
-					edid_ctrl, i, edid_buf+0x00);
+					edid_ctrl, i, edid_buf + (0x80 * i));
 				if (status) {
 					DEV_ERR("%s: read blk(%d) failed:%d\n",
 						__func__, i, status);
@@ -1399,7 +1447,7 @@
 				}
 			} else {
 				status = hdmi_edid_read_block(
-					edid_ctrl, i, edid_buf+0x80);
+					edid_ctrl, i, edid_buf + (0x80 * i));
 				if (status) {
 					DEV_ERR("%s: read blk(%d) failed:%d\n",
 						__func__, i, status);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 367c918..80b27ed 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -17,6 +17,7 @@
 #include <linux/stat.h>
 
 #include "mdss_hdmi_hdcp.h"
+#include "video/msm_hdmi_hdcp_mgr.h"
 
 #define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state))
 
@@ -31,7 +32,11 @@
 #define HDCP_KEYS_STATE_RESERVED	7
 
 struct hdmi_hdcp_ctrl {
+	u32 auth_retries;
+	u32 tp_msgid;
 	enum hdmi_hdcp_state hdcp_state;
+	struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+	struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
 	struct delayed_work hdcp_auth_work;
 	struct work_struct hdcp_int_work;
 	struct completion r0_checked;
@@ -194,7 +199,7 @@
 	bool is_match;
 	bool stale_an = false;
 	struct dss_io_data *io;
-	u8 aksv[5], bksv[5];
+	u8 aksv[5], *bksv = NULL;
 	u8 an[8];
 	u8 bcaps;
 	struct hdmi_tx_ddc_data ddc_data;
@@ -215,6 +220,8 @@
 		goto error;
 	}
 
+	bksv = hdcp_ctrl->current_tp.bksv;
+
 	io = hdcp_ctrl->init_data.core_io;
 
 	/* Fetch aksv from QFPROM, this info should be public. */
@@ -606,11 +613,12 @@
 {
 	int rc, cnt, i;
 	struct hdmi_tx_ddc_data ddc_data;
-	u32 timeout_count, down_stream_devices;
+	u32 timeout_count, down_stream_devices = 0;
+	u32 repeater_cascade_depth = 0;
 	u8 buf[0xFF];
-	u8 ksv_fifo[5 * 127];
+	u8 *ksv_fifo = NULL;
 	u8 bcaps;
-	u16 bstatus, max_devs_exceeded, max_cascade_exceeded;
+	u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0;
 	u32 link0_status;
 	u32 ksv_bytes;
 	struct dss_io_data *io;
@@ -628,10 +636,13 @@
 		goto error;
 	}
 
+	ksv_fifo = hdcp_ctrl->current_tp.ksv_list;
+
 	io = hdcp_ctrl->init_data.core_io;
 
 	memset(buf, 0, sizeof(buf));
-	memset(ksv_fifo, 0, sizeof(ksv_fifo));
+	memset(ksv_fifo, 0,
+		sizeof(hdcp_ctrl->current_tp.ksv_list));
 
 	/* Read BCAPS at offset 0x40 */
 	memset(&ddc_data, 0, sizeof(ddc_data));
@@ -652,6 +663,10 @@
 	DEV_DBG("%s: %s: BCAPS=%02x (%s)\n", __func__, HDCP_STATE_NAME, bcaps,
 		(bcaps & BIT(6)) ? "repeater" : "no repeater");
 
+	/* receiver (0), repeater (1) */
+	hdcp_ctrl->current_tp.ds_type =
+		(bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
+
 	/* if REPEATER (Bit 6), perform Part2 Authentication */
 	if (!(bcaps & BIT(6))) {
 		DEV_INFO("%s: %s: auth part II skipped, no repeater\n",
@@ -717,6 +732,9 @@
 		goto error;
 	}
 
+	/* Cascaded repeater depth */
+	repeater_cascade_depth = (bstatus >> 8) & 0x7;
+
 	/*
 	 * HDCP Compliance 1B-05:
 	 * Check if no. of devices connected to repeater
@@ -866,9 +884,46 @@
 	else
 		DEV_INFO("%s: %s: Authentication Part II successful\n",
 			__func__, HDCP_STATE_NAME);
+
+	/* Update topology information */
+	hdcp_ctrl->current_tp.dev_count = down_stream_devices;
+	hdcp_ctrl->current_tp.max_cascade_exceeded = max_cascade_exceeded;
+	hdcp_ctrl->current_tp.max_dev_exceeded = max_devs_exceeded;
+	hdcp_ctrl->current_tp.depth = repeater_cascade_depth;
+
 	return rc;
 } /* hdmi_hdcp_authentication_part2 */
 
+static void hdmi_hdcp_cache_topology(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	memcpy((void *)&hdcp_ctrl->cached_tp,
+		(void *) &hdcp_ctrl->current_tp,
+		sizeof(hdcp_ctrl->cached_tp));
+}
+
+static void hdmi_hdcp_notify_topology(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+	char a[16], b[16];
+	char *envp[] = {
+		[0] = "HDCP_MGR_EVENT=MSG_READY",
+		[1] = a,
+		[2] = b,
+		NULL,
+	};
+
+	snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
+	snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
+	kobject_uevent_env(hdcp_ctrl->init_data.sysfs_kobj, KOBJ_CHANGE, envp);
+
+	DEV_DBG("%s Event Sent: %s msgID = %s srcID = %s\n", __func__,
+			envp[0], envp[1], envp[2]);
+}
+
 static void hdmi_hdcp_int_work(struct work_struct *work)
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
@@ -928,7 +983,7 @@
 		goto error;
 	}
 	/* Disabling software DDC before going into part3 to make sure
-	 * there is no Arbitratioon between software and hardware for DDC */
+	 * there is no Arbitration between software and hardware for DDC */
 	DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io,
 				HDMI_DDC_ARBITRATION) | (BIT(4)));
 
@@ -941,10 +996,14 @@
 	 */
 	mutex_lock(hdcp_ctrl->init_data.mutex);
 	if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
-		if (rc)
+		if (rc) {
 			hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL;
-		else
+		} else {
 			hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
+			hdcp_ctrl->auth_retries = 0;
+			hdmi_hdcp_cache_topology(hdcp_ctrl);
+			hdmi_hdcp_notify_topology(hdcp_ctrl);
+		}
 		mutex_unlock(hdcp_ctrl->init_data.mutex);
 
 		/* Notify HDMI Tx controller of the result */
@@ -989,10 +1048,38 @@
 	return 0;
 } /* hdmi_hdcp_authenticate */
 
+/*
+ * Only retries defined times then abort current authenticating process
+ * Send check_topology message to notify any hdcpmanager's client of non-
+ * hdcp authenticated data link so the client can tear down any active secure
+ * playback.
+ * Reduce hdcp link to regular hdmi data link with hdcp disabled so any
+ * un-secure like UI & menu still can be sent over HDMI and display.
+ */
+#define AUTH_RETRIES_TIME (30)
+static int hdmi_msm_if_abort_reauth(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+	int ret = 0;
+
+	if (!hdcp_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) {
+		hdmi_hdcp_off(hdcp_ctrl);
+		hdcp_ctrl->auth_retries = 0;
+		ret = -ERANGE;
+	}
+
+	return ret;
+}
+
 int hdmi_hdcp_reauthenticate(void *input)
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
 	struct dss_io_data *io;
+	u32 ret = 0;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -1001,13 +1088,19 @@
 
 	io = hdcp_ctrl->init_data.core_io;
 
-
 	if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
 		DEV_DBG("%s: %s: invalid state. returning\n", __func__,
 			HDCP_STATE_NAME);
 		return 0;
 	}
 
+	ret = hdmi_msm_if_abort_reauth(hdcp_ctrl);
+
+	if (ret) {
+		DEV_ERR("%s: abort reauthentication!\n", __func__);
+		return ret;
+	}
+
 	/*
 	 * Disable HPD circuitry.
 	 * This is needed to reset the HDCP cipher engine so that when we
@@ -1042,7 +1135,7 @@
 	queue_delayed_work(hdcp_ctrl->init_data.workq,
 		&hdcp_ctrl->hdcp_auth_work, HZ/2);
 
-	return 0;
+	return ret;
 } /* hdmi_hdcp_reauthenticate */
 
 void hdmi_hdcp_off(void *input)
@@ -1092,9 +1185,6 @@
 
 	DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
 
-	/* Wait to be clean on DDC HW engine */
-	hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
-
 	/* Disable encryption and disable the HDCP block */
 	DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
 
@@ -1192,10 +1282,76 @@
 	return ret;
 } /* hdmi_hdcp_sysfs_rda_hdcp*/
 
+static ssize_t hdmi_hdcp_sysfs_rda_tp(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	struct hdmi_hdcp_ctrl *hdcp_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP);
+
+	if (!hdcp_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (hdcp_ctrl->tp_msgid) {
+	case DOWN_CHECK_TOPOLOGY:
+	case DOWN_REQUEST_TOPOLOGY:
+		buf[MSG_ID_IDX]   = hdcp_ctrl->tp_msgid;
+		buf[RET_CODE_IDX] = HDCP_AUTHED;
+		ret = HEADER_LEN;
+
+		memcpy(buf + HEADER_LEN, &hdcp_ctrl->cached_tp,
+			sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+
+		ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
+
+		/* clear the flag once data is read back to user space*/
+		hdcp_ctrl->tp_msgid = -1;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+} /* hdmi_hdcp_sysfs_rda_tp*/
+
+static ssize_t hdmi_hdcp_sysfs_wta_tp(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int msgid = 0;
+	ssize_t ret = count;
+	struct hdmi_hdcp_ctrl *hdcp_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP);
+
+	if (!hdcp_ctrl || !buf) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	msgid = buf[0];
+
+	switch (msgid) {
+	case DOWN_CHECK_TOPOLOGY:
+	case DOWN_REQUEST_TOPOLOGY:
+		hdcp_ctrl->tp_msgid = msgid;
+		break;
+	/* more cases added here */
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_hpd */
+
 static DEVICE_ATTR(status, S_IRUGO, hdmi_hdcp_sysfs_rda_status, NULL);
+static DEVICE_ATTR(tp, S_IRUGO | S_IWUSR, hdmi_hdcp_sysfs_rda_tp,
+	hdmi_hdcp_sysfs_wta_tp);
+
 
 static struct attribute *hdmi_hdcp_fs_attrs[] = {
 	&dev_attr_status.attr,
+	&dev_attr_tp.attr,
 	NULL,
 };
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 7117779..e46e361 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -46,6 +46,14 @@
 #define HPD_DISCONNECT_POLARITY 0
 #define HPD_CONNECT_POLARITY    1
 
+/*
+ * Audio engine may take 1 to 3 sec to shutdown
+ * in normal cases. To handle worst cases, making
+ * timeout for audio engine shutdown as 5 sec.
+ */
+#define AUDIO_POLL_SLEEP_US   (5 * 1000)
+#define AUDIO_POLL_TIMEOUT_US (AUDIO_POLL_SLEEP_US * 1000)
+
 #define IFRAME_CHECKSUM_32(d)			\
 	((d & 0xff) + ((d >> 8) & 0xff) +	\
 	((d >> 16) & 0xff) + ((d >> 24) & 0xff))
@@ -87,8 +95,8 @@
 static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
 static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
 	enum hdmi_tx_power_module_type module, int enable);
-static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl,
-				bool wait_audio_tx);
+static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
+	int val, bool force);
 static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl);
 
 struct mdss_hw hdmi_tx_hw = {
@@ -126,7 +134,13 @@
 	}
 } /* hdmi_pm_name */
 
-static u8 hdmi_tx_avi_iframe_lut[][20] = {
+static DEFINE_MUTEX(avi_iframe_lut_lock);
+#define NUM_MODES_AVI 20
+#define SET_ITC_BIT(byte)  (byte | 0x80)
+#define CLR_ITC_BIT(byte)  (byte & 0x7F)
+#define CONFIG_CN_BITS(bits, byte)  ((byte & ~(0x03 << 4)) | (bits << 4))
+
+static u8 hdmi_tx_avi_iframe_lut[][NUM_MODES_AVI] = {
 	{0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
 	 0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
 	 0x10,	0x10}, /*00*/
@@ -193,6 +207,55 @@
 		{20480, 247500} } },
 };
 
+/* To statically config ITC bit from sysfs attribute */
+static int hdmi_tx_config_itc_bit(int itc)
+{
+	int ret = 0, loop = NUM_MODES_AVI;
+
+	if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
+		ret = -ERESTARTSYS;
+		goto signal_intr;
+	}
+
+	do {
+		--loop;
+		if (itc == 0)
+			hdmi_tx_avi_iframe_lut[2][loop] =
+				CLR_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
+		if (itc == 1)
+			hdmi_tx_avi_iframe_lut[2][loop] =
+				SET_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
+	} while (loop);
+
+	mutex_unlock(&avi_iframe_lut_lock);
+
+signal_intr:
+	return ret;
+}
+
+/* To configure CN0_1 bits from sysfs attribute */
+static int hdmi_tx_config_cn_bits(int cns)
+{
+	int ret = 0, loop = NUM_MODES_AVI;
+
+	if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
+		ret = -ERESTARTSYS;
+		goto signal_intr;
+	}
+
+	do {
+		--loop;
+		hdmi_tx_avi_iframe_lut[4][loop] =
+			CONFIG_CN_BITS(cns, hdmi_tx_avi_iframe_lut[4][loop]);
+	} while (loop);
+
+	mutex_unlock(&avi_iframe_lut_lock);
+
+signal_intr:
+	return ret;
+}
+
+
 static bool hdmi_tx_is_cea_format(int mode)
 {
 	bool cea_fmt;
@@ -288,6 +351,52 @@
 	return new_vic;
 } /* hdmi_tx_get_vic_from_panel_info */
 
+static inline void hdmi_tx_send_cable_notification(
+	struct hdmi_tx_ctrl *hdmi_ctrl, int val)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
+		switch_set_state(&hdmi_ctrl->sdev, val);
+} /* hdmi_tx_send_cable_notification */
+
+static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	return hdmi_edid_get_sink_mode(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
+} /* hdmi_tx_is_dvi_mode */
+
+static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	u32 status = 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 not inititalized\n", __func__);
+		return;
+	}
+
+	if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status,
+				(status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
+				AUDIO_POLL_TIMEOUT_US))
+		DEV_ERR("%s: Error turning off audio packet transmission.\n",
+			__func__);
+
+	if (readl_poll_timeout(io->base + HDMI_AUDIO_CFG, status,
+				(status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
+				AUDIO_POLL_TIMEOUT_US))
+		DEV_ERR("%s: Error turning off audio engine.\n", __func__);
+}
+
 static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data(
 	struct mdss_panel_data *mpd)
 {
@@ -406,6 +515,15 @@
 
 	if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
 		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+
+		if (hdmi_ctrl->panel_power_on && hdmi_ctrl->hpd_state) {
+			hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
+			hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
+		}
+
+		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
+		DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
 	} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
 		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
 	} else {
@@ -544,6 +662,58 @@
 	return ret;
 } /* hdmi_tx_sysfs_rda_product_description */
 
+static ssize_t hdmi_tx_sysfs_wta_avi_itc(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err = 0;
+	int itc = 0, rc = 0;
+
+	rc = kstrtoint(buf, 10, &itc);
+	if (rc) {
+		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	if (itc == 0 || itc == 1) {
+		if (hdmi_tx_config_itc_bit(itc))
+			ret = err;
+		else
+			DEV_DBG("%s: '%d is configured'!\n", __func__, itc);
+	} else {
+		DEV_ERR("%s: unknown ITC '%d', should be either 0 or 1\n",
+				__func__, itc);
+	}
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_avi_itc */
+
+static ssize_t hdmi_tx_sysfs_wta_avi_cn0_1(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err = 0;
+	int cns = 0, rc = 0;
+
+	rc = kstrtoint(buf, 10, &cns);
+	if (rc) {
+		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	if (cns == 0 || cns == 1 || cns == 2 || cns == 3) {
+		if (hdmi_tx_config_cn_bits(cns))
+			ret = err;
+		else
+			DEV_DBG("%s: '%d is configured'!\n", __func__, cns);
+	} else {
+		DEV_ERR("%s: unknown CN '%d' should be either 0 or 1, 2 ,3\n",
+				__func__, cns);
+	}
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_avi_cn0_1 */
+
 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);
@@ -552,12 +722,16 @@
 static DEVICE_ATTR(product_description, S_IRUGO | S_IWUSR,
 	hdmi_tx_sysfs_rda_product_description,
 	hdmi_tx_sysfs_wta_product_description);
+static DEVICE_ATTR(avi_itc, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_itc);
+static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn0_1);
 
 static struct attribute *hdmi_tx_fs_attrs[] = {
 	&dev_attr_connected.attr,
 	&dev_attr_hpd.attr,
 	&dev_attr_vendor_name.attr,
 	&dev_attr_product_description.attr,
+	&dev_attr_avi_itc.attr,
+	&dev_attr_avi_cn0_1.attr,
 	NULL,
 };
 static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -597,24 +771,6 @@
 	hdmi_ctrl->kobj = NULL;
 } /* hdmi_tx_sysfs_remove */
 
-static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
-{
-	return hdmi_edid_get_sink_mode(
-		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
-} /* hdmi_tx_is_dvi_mode */
-
-static inline void hdmi_tx_send_cable_notification(
-	struct hdmi_tx_ctrl *hdmi_ctrl, int val)
-{
-	if (!hdmi_ctrl) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return;
-	}
-
-	if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
-		switch_set_state(&hdmi_ctrl->sdev, val);
-} /* hdmi_tx_send_cable_notification */
-
 static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
 	int val, bool force)
 {
@@ -901,8 +1057,8 @@
 		DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
 			__func__, hdmi_ctrl->sdev.state);
 	} else {
-		if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false))
-			DEV_WARN("%s: Failed to disable ddc power\n", __func__);
+		hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
+		hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
 
 		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
 		DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
@@ -2134,10 +2290,8 @@
 	return 0;
 } /* hdmi_tx_audio_setup */
 
-static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl,
-				bool wait_audio_tx)
+static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	u32 i = 0, status, sleep_us, timeout_us, timeout_sec = 15;
 	struct dss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
@@ -2151,34 +2305,6 @@
 		return;
 	}
 
-	if (wait_audio_tx) {
-		/* Check if audio engine is turned off by QDSP or not */
-		/* send off notification after every 1 sec for 15 seconds */
-		for (i = 0; i < timeout_sec; i++) {
-			/* Maximum time to sleep between two reads */
-			sleep_us = 5000;
-			/* Total time for condition to meet */
-			timeout_us = 1000 * 1000;
-
-			if (readl_poll_timeout((io->base + HDMI_AUDIO_CFG),
-				status, ((status & BIT(0)) == 0),
-				sleep_us, timeout_us)) {
-
-				DEV_ERR(
-				"%s: audio still on after %d sec. try again\n",
-				__func__, i+1);
-
-				hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0,
-					true);
-				continue;
-			}
-			break;
-		}
-	}
-
-	if (i == timeout_sec)
-		DEV_ERR("%s: Error: cannot turn off audio engine\n", __func__);
-
 	if (hdmi_tx_audio_iframe_setup(hdmi_ctrl, false))
 		DEV_ERR("%s: hdmi_tx_audio_iframe_setup failed.\n", __func__);
 
@@ -2302,10 +2428,11 @@
 		hdmi_hdcp_off(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
 	}
 
-	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
-		hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
-		hdmi_tx_audio_off(hdmi_ctrl, true);
-	}
+	if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false))
+		DEV_WARN("%s: Failed to disable ddc power\n", __func__);
+
+	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
+		hdmi_tx_audio_off(hdmi_ctrl);
 
 	hdmi_tx_powerdown_phy(hdmi_ctrl);
 
@@ -2556,10 +2683,6 @@
 			hdmi_tx_hpd_off(hdmi_ctrl);
 		else
 			hdmi_ctrl->hpd_off_pending = true;
-
-		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
-		DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
 	}
 
 	return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 4a4684b..3afe2c7 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -79,6 +79,7 @@
 
 static DEFINE_SPINLOCK(mdp_lock);
 static DEFINE_MUTEX(mdp_clk_lock);
+static DEFINE_MUTEX(bus_bw_lock);
 
 #define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
 	{						\
@@ -608,9 +609,58 @@
 	return clk_rate;
 }
 
+/**
+ * mdss_bus_bandwidth_ctrl() -- place bus bandwidth request
+ * @enable:	value of enable or disable
+ *
+ * Function place bus bandwidth request to allocate saved bandwidth
+ * if enabled or free bus bandwidth allocation if disabled.
+ * Bus bandwidth is required by mdp.For dsi, it only requires to send
+ * dcs coammnd.
+ */
+void mdss_bus_bandwidth_ctrl(int enable)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	static int bus_bw_cnt;
+	int changed = 0;
+
+	mutex_lock(&bus_bw_lock);
+	if (enable) {
+		if (bus_bw_cnt == 0)
+			changed++;
+		bus_bw_cnt++;
+	} else {
+		if (bus_bw_cnt) {
+			bus_bw_cnt--;
+			if (bus_bw_cnt == 0)
+				changed++;
+		} else {
+			pr_err("Can not be turned off\n");
+		}
+	}
+
+	pr_debug("bw_cnt=%d changed=%d enable=%d\n",
+			bus_bw_cnt, changed, enable);
+
+	if (changed) {
+		if (!enable) {
+			msm_bus_scale_client_update_request(
+				mdata->bus_hdl, 0);
+			pm_runtime_put(&mdata->pdev->dev);
+		} else {
+			pm_runtime_get_sync(&mdata->pdev->dev);
+			msm_bus_scale_client_update_request(
+				mdata->bus_hdl, mdata->current_bus_idx);
+		}
+	}
+
+	mutex_unlock(&bus_bw_lock);
+}
+EXPORT_SYMBOL(mdss_bus_bandwidth_ctrl);
+
 void mdss_mdp_clk_ctrl(int enable, int isr)
 {
-	struct mdss_data_type *mdata = mdss_res;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	static int mdp_clk_cnt;
 	int changed = 0;
 
@@ -620,9 +670,13 @@
 			changed++;
 		mdp_clk_cnt++;
 	} else {
-		mdp_clk_cnt--;
-		if (mdp_clk_cnt == 0)
-			changed++;
+		if (mdp_clk_cnt) {
+			mdp_clk_cnt--;
+			if (mdp_clk_cnt == 0)
+				changed++;
+		} else {
+			pr_err("Can not be turned off\n");
+		}
 	}
 
 	pr_debug("%s: clk_cnt=%d changed=%d enable=%d\n",
@@ -640,14 +694,10 @@
 		if (mdata->vsync_ena)
 			mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
 
-		if (!enable) {
-			msm_bus_scale_client_update_request(
-				mdss_res->bus_hdl, 0);
+		mdss_bus_bandwidth_ctrl(enable);
+
+		if (!enable)
 			pm_runtime_put(&mdata->pdev->dev);
-		} else {
-			msm_bus_scale_client_update_request(
-				mdss_res->bus_hdl, mdss_res->current_bus_idx);
-		}
 	}
 
 	mutex_unlock(&mdp_clk_lock);
@@ -1771,7 +1821,8 @@
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
 	u32 num;
 	u32 data[2];
-	int rc;
+	int rc, len;
+	const u32 *arr;
 
 	num = mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-smp-data");
 
@@ -1793,7 +1844,49 @@
 		"qcom,mdss-smp-mb-per-pipe", data);
 	mdata->smp_mb_per_pipe = (!rc ? data[0] : 0);
 
-	return 0;
+	rc = 0;
+	arr = of_get_property(pdev->dev.of_node,
+		"qcom,mdss-pipe-rgb-fixed-mmb", &len);
+	if (arr) {
+		int i, j, k;
+		u32 cnt, mmb;
+
+		len /= sizeof(u32);
+		for (i = 0, k = 0; i < len; k++) {
+			struct mdss_mdp_pipe *pipe = NULL;
+
+			if (k >= mdata->nrgb_pipes) {
+				pr_err("invalid fixed mmbs for rgb pipes\n");
+				return -EINVAL;
+			}
+
+			pipe = &mdata->rgb_pipes[k];
+
+			cnt = be32_to_cpu(arr[i++]);
+			if (cnt == 0)
+				continue;
+
+			for (j = 0; j < cnt; j++) {
+				mmb = be32_to_cpu(arr[i++]);
+				if (mmb > mdata->smp_mb_cnt) {
+					pr_err("overflow mmb%d: rgb%d: max%d\n",
+						mmb, k, mdata->smp_mb_cnt);
+					return -EINVAL;
+				}
+				/* rgb pipes fetches only single plane */
+				set_bit(mmb, pipe->smp_map[0].fixed);
+			}
+			if (bitmap_intersects(pipe->smp_map[0].fixed,
+				mdata->mmb_alloc_map, mdata->smp_mb_cnt)) {
+				pr_err("overlapping fixed mmb map\n");
+				return -EINVAL;
+			}
+			bitmap_or(mdata->mmb_alloc_map, pipe->smp_map[0].fixed,
+				mdata->mmb_alloc_map, mdata->smp_mb_cnt);
+		}
+	}
+
+	return rc;
 }
 
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
@@ -1801,6 +1894,7 @@
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
 	u32 data;
 	int rc;
+	struct property *prop = NULL;
 
 	rc = of_property_read_u32(pdev->dev.of_node, "qcom,mdss-rot-block-size",
 		&data);
@@ -1812,6 +1906,9 @@
 		"qcom,mdss-has-decimation");
 	mdata->has_wfd_blk = of_property_read_bool(pdev->dev.of_node,
 		"qcom,mdss-has-wfd-blk");
+	prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
+	mdata->batfet_required = prop ? true : false;
+
 	return 0;
 }
 
@@ -1983,6 +2080,33 @@
 	return rc;
 }
 
+void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable)
+{
+	if (!mdata->batfet_required)
+		return;
+
+	if (!mdata->batfet) {
+		if (enable) {
+			mdata->batfet = devm_regulator_get(&mdata->pdev->dev,
+				"batfet");
+			if (IS_ERR_OR_NULL(mdata->batfet)) {
+				pr_debug("unable to get batfet reg. rc=%d\n",
+					PTR_RET(mdata->batfet));
+				mdata->batfet = NULL;
+				return;
+			}
+		} else {
+			pr_debug("Batfet regulator disable w/o enable\n");
+			return;
+		}
+	}
+
+	if (enable)
+		regulator_enable(mdata->batfet);
+	else
+		regulator_disable(mdata->batfet);
+}
+
 static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
 {
 	if (!mdata->fs)
@@ -1993,6 +2117,7 @@
 		if (!mdata->fs_ena) {
 			regulator_enable(mdata->fs);
 			mdss_mdp_cx_ctrl(mdata, true);
+			mdss_mdp_batfet_ctrl(mdata, true);
 		}
 		mdata->fs_ena = true;
 	} else {
@@ -2001,6 +2126,7 @@
 		if (mdata->fs_ena) {
 			regulator_disable(mdata->fs);
 			mdss_mdp_cx_ctrl(mdata, false);
+			mdss_mdp_batfet_ctrl(mdata, false);
 		}
 		mdata->fs_ena = false;
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 1fca37d..d8dc6ca 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -18,9 +18,11 @@
 #include <linux/io.h>
 #include <linux/msm_mdp.h>
 #include <linux/platform_device.h>
+#include <linux/notifier.h>
 
 #include "mdss.h"
 #include "mdss_mdp_hwio.h"
+#include "mdss_fb.h"
 
 #define MDSS_MDP_DEFAULT_INTR_MASK 0
 #define MDSS_MDP_CURSOR_WIDTH 64
@@ -187,6 +189,9 @@
 	int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
 					struct mdss_mdp_vsync_handler *);
 	int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, int new_fps);
+
+	struct blocking_notifier_head notifier_head;
+
 	void *priv_data;
 	u32 wb_type;
 };
@@ -311,8 +316,9 @@
 };
 
 struct mdss_mdp_pipe_smp_map {
-	DECLARE_BITMAP(reserved, MDSS_MDP_SMP_MMB_BLOCKS);
-	DECLARE_BITMAP(allocated, MDSS_MDP_SMP_MMB_BLOCKS);
+	DECLARE_BITMAP(reserved, MAX_DRV_SUP_MMB_BLKS);
+	DECLARE_BITMAP(allocated, MAX_DRV_SUP_MMB_BLKS);
+	DECLARE_BITMAP(fixed, MAX_DRV_SUP_MMB_BLKS);
 };
 
 struct mdss_mdp_pipe {
@@ -324,6 +330,7 @@
 	atomic_t ref_cnt;
 	u32 play_cnt;
 	int pid;
+	bool is_handed_off;
 
 	u32 flags;
 	u32 bwc_mode;
@@ -393,6 +400,7 @@
 	int free_list_size;
 	int ad_state;
 
+	bool handoff;
 	u32 splash_mem_addr;
 	u32 splash_mem_size;
 	u32 sd_enabled;
@@ -451,6 +459,7 @@
 			       void (*fnc_ptr)(void *), void *arg);
 
 void mdss_mdp_footswitch_ctrl_splash(int on);
+void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
 int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota);
 void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
 unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
@@ -459,7 +468,15 @@
 struct mdss_data_type *mdss_mdp_get_mdata(void);
 
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
+			       struct mdp_overlay *req,
+			       struct mdss_mdp_format_params *fmt);
 int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en);
+int mdss_mdp_overlay_get_buf(struct msm_fb_data_type *mfd,
+			     struct mdss_mdp_data *data,
+			     struct msmfb_data *planes,
+			     int num_planes,
+			     u32 flags);
 int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
 		u32 *offsets,  u32 count);
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
@@ -470,9 +487,11 @@
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
 					struct msm_fb_data_type *mfd);
-int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
+		bool handoff);
+int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
+		bool handoff);
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
@@ -482,7 +501,14 @@
 int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
 int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
 		struct mdss_mdp_perf_params *perf);
+int mdss_mdp_ctl_notify(struct mdss_mdp_ctl *ctl, int event);
+void mdss_mdp_ctl_notifier_register(struct mdss_mdp_ctl *ctl,
+	struct notifier_block *notifier);
+void mdss_mdp_ctl_notifier_unregister(struct mdss_mdp_ctl *ctl,
+	struct notifier_block *notifier);
 
+int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num,
+	struct mdss_mdp_pipe *pipe);
 struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
 int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
 struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
@@ -536,6 +562,8 @@
 int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
 				struct mdss_calib_cfg *cfg);
 
+int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_smp_handoff(struct mdss_data_type *mdata);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
 					  u32 type);
 struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx);
@@ -572,6 +600,7 @@
 struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
+int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data);
 u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
 int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase);
 void mdss_mdp_intersect_rect(struct mdss_mdp_img_rect *res_rect,
@@ -609,4 +638,5 @@
 #define mfd_to_wb(mfd) (((struct mdss_overlay_private *)\
 				(mfd->mdp.private1))->wb)
 
+int  mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl);
 #endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index ec7bc11..82937e3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -16,6 +16,8 @@
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
@@ -383,6 +385,7 @@
 			ctl->ref_cnt++;
 			ctl->mdata = mdata;
 			mutex_init(&ctl->lock);
+			BLOCKING_INIT_NOTIFIER_HEAD(&ctl->notifier_head);
 			pr_debug("alloc ctl_num=%d\n", ctl->num);
 			break;
 		}
@@ -608,13 +611,13 @@
 	return 0;
 }
 
-int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff)
 {
 	switch (ctl->panel_data->panel_info.type) {
 	case MIPI_VIDEO_PANEL:
-		return mdss_mdp_video_reconfigure_splash_done(ctl);
+		return mdss_mdp_video_reconfigure_splash_done(ctl, handoff);
 	case MIPI_CMD_PANEL:
-		return mdss_mdp_cmd_reconfigure_splash_done(ctl);
+		return mdss_mdp_cmd_reconfigure_splash_done(ctl, handoff);
 	default:
 		return 0;
 	}
@@ -1076,9 +1079,12 @@
 
 	pr_debug("ctl_num=%d\n", ctl->num);
 
-	nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER + MDSS_MDP_WB_MAX_LAYERMIXER;
-	for (i = 0; i < nmixers; i++)
-		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0);
+	if (!ctl->panel_data->panel_info.cont_splash_enabled) {
+		nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER +
+			MDSS_MDP_WB_MAX_LAYERMIXER;
+		for (i = 0; i < nmixers; i++)
+			mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0);
+	}
 
 	mixer = ctl->mixer_left;
 	mdss_mdp_pp_resume(ctl, mixer->num);
@@ -1259,6 +1265,41 @@
 			ctl->roi.x, ctl->roi.y, ctl->roi.w, ctl->roi.h);
 }
 
+/*
+ * mdss_mdp_ctl_reset() - reset mdp ctl path.
+ * @ctl: mdp controller.
+ * this function called when underflow happen,
+ * it will reset mdp ctl path and poll for its completion
+ *
+ * Note: called within atomic context.
+ */
+int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl)
+{
+	u32 status = 1;
+	int cnt = 20;
+
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_SW_RESET, 1);
+
+	/*
+	 * it takes around 30us to have mdp finish resetting its ctl path
+	 * poll every 50us so that reset should be completed at 1st poll
+	 */
+
+	do {
+		udelay(50);
+		status = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_SW_RESET);
+		status &= 0x01;
+		pr_debug("status=%x\n", status);
+		cnt--;
+		if (cnt == 0) {
+			pr_err("timeout\n");
+			return -EAGAIN;
+		}
+	} while (status);
+
+	return 0;
+}
+
 static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
 				struct mdss_mdp_mixer *mixer)
 {
@@ -1833,6 +1874,11 @@
 		}
 	}
 
+	mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
+
+	if (ctl->wait_pingpong)
+		ctl->wait_pingpong(ctl, NULL);
+
 	/* postprocessing setup, including dspp */
 	mdss_mdp_pp_setup_locked(ctl);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
@@ -1858,6 +1904,23 @@
 	return ret;
 }
 
+void mdss_mdp_ctl_notifier_register(struct mdss_mdp_ctl *ctl,
+	struct notifier_block *notifier)
+{
+	blocking_notifier_chain_register(&ctl->notifier_head, notifier);
+}
+
+void mdss_mdp_ctl_notifier_unregister(struct mdss_mdp_ctl *ctl,
+	struct notifier_block *notifier)
+{
+	blocking_notifier_chain_unregister(&ctl->notifier_head, notifier);
+}
+
+int mdss_mdp_ctl_notify(struct mdss_mdp_ctl *ctl, int event)
+{
+	return blocking_notifier_call_chain(&ctl->notifier_head, event, ctl);
+}
+
 int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id)
 {
 	int i;
@@ -1928,3 +1991,66 @@
 				MDSS_MDP_INTF_LAYERMIXER3);
 	}
 }
+
+static int __mdss_mdp_mixer_handoff_helper(struct mdss_mdp_mixer *mixer,
+	struct mdss_mdp_pipe *pipe)
+{
+	int rc = 0;
+
+	if (!mixer) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] != NULL) {
+		pr_err("More than one pipe staged on mixer num %d\n",
+			mixer->num);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	pr_debug("Staging pipe num %d on mixer num %d\n",
+		pipe->num, mixer->num);
+	mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] = pipe;
+	pipe->mixer = mixer;
+	pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
+
+error:
+	return rc;
+}
+
+/**
+ * mdss_mdp_mixer_handoff() - Stages a given pipe on the appropriate mixer
+ * @ctl:  pointer to the control structure associated with the overlay device.
+ * @num:  the mixer number on which the pipe needs to be staged.
+ * @pipe: pointer to the pipe to be staged.
+ *
+ * Function stages a given pipe on either the left mixer or the right mixer
+ * for the control structre based on the mixer number. If the input mixer
+ * number does not match either of the mixers then an error is returned.
+ * This function is called during overlay handoff when certain pipes are
+ * already staged by the bootloader.
+ */
+int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num,
+	struct mdss_mdp_pipe *pipe)
+{
+	int rc = 0;
+	struct mdss_mdp_mixer *mx_left = ctl->mixer_left;
+	struct mdss_mdp_mixer *mx_right = ctl->mixer_right;
+
+	/*
+	 * For performance calculations, stage the handed off pipe
+	 * as MDSS_MDP_STAGE_UNUSED
+	 */
+	if (mx_left && (mx_left->num == num)) {
+		rc = __mdss_mdp_mixer_handoff_helper(mx_left, pipe);
+	} else if (mx_right && (mx_right->num == num)) {
+		rc = __mdss_mdp_mixer_handoff_helper(mx_right, pipe);
+	} else {
+		pr_err("pipe num %d staged on unallocated mixer num %d\n",
+			pipe->num, num);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 213368a..c8af903 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -114,6 +114,7 @@
 #define MDSS_MDP_REG_CTL_FLUSH				0x018
 #define MDSS_MDP_REG_CTL_START				0x01C
 #define MDSS_MDP_REG_CTL_PACK_3D			0x020
+#define MDSS_MDP_REG_CTL_SW_RESET			0x030
 
 #define MDSS_MDP_CTL_OP_VIDEO_MODE		(0 << 17)
 #define MDSS_MDP_CTL_OP_CMD_MODE		(1 << 17)
@@ -418,8 +419,6 @@
 	MDSS_MDP_MAX_INTF
 };
 
-#define MDSS_MDP_REG_INTF_OFFSET(intf)		(0x20F00 + ((intf) * 0x200))
-
 #define MDSS_MDP_REG_INTF_TIMING_ENGINE_EN		0x000
 #define MDSS_MDP_REG_INTF_CONFIG			0x004
 #define MDSS_MDP_REG_INTF_HSYNC_CTL			0x008
@@ -498,8 +497,6 @@
 #define MDSS_MDP_REG_SMP_ALLOC_W0			0x00180
 #define MDSS_MDP_REG_SMP_ALLOC_R0			0x00230
 
-#define MDSS_MDP_SMP_MMB_BLOCKS			44
-
 #define MDSS_MDP_LP_MISR_SEL			0x450
 #define MDSS_MDP_LP_MISR_CTRL_MDP		0x454
 #define MDSS_MDP_LP_MISR_CTRL_HDMI		0x458
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index addb9b0..6056f21 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -12,9 +12,9 @@
  */
 
 #include <linux/kernel.h>
-#include "mdss_panel.h"
+
 #include "mdss_mdp.h"
-#include "mdss_dsi.h"
+#include "mdss_panel.h"
 
 #define VSYNC_EXPIRE_TICK 4
 
@@ -43,6 +43,8 @@
 	struct mutex clk_mtx;
 	spinlock_t clk_lock;
 	struct work_struct clk_work;
+	struct work_struct pp_done_work;
+	atomic_t pp_done_cnt;
 
 	/* te config */
 	u8 tear_check;
@@ -50,6 +52,7 @@
 	u16 vporch;	/* vertical porches */
 	u16 start_threshold;
 	u32 vclk_line;	/* vsync clock per line */
+	struct mdss_panel_recovery recovery;
 };
 
 struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@@ -264,6 +267,31 @@
 	spin_unlock(&ctx->clk_lock);
 }
 
+static void mdss_mdp_cmd_underflow_recovery(void *data)
+{
+	struct mdss_mdp_cmd_ctx *ctx = data;
+	unsigned long flags;
+
+	if (!data) {
+		pr_err("%s: invalid ctx\n", __func__);
+		return;
+	}
+
+	if (!ctx->ctl)
+		return;
+	spin_lock_irqsave(&ctx->clk_lock, flags);
+	if (ctx->koff_cnt) {
+		mdss_mdp_ctl_reset(ctx->ctl);
+		pr_debug("%s: intf_num=%d\n", __func__,
+					ctx->ctl->intf_num);
+		ctx->koff_cnt--;
+		mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
+						ctx->pp_num);
+		complete_all(&ctx->pp_comp);
+	}
+	spin_unlock_irqrestore(&ctx->clk_lock, flags);
+}
+
 static void mdss_mdp_cmd_pingpong_done(void *arg)
 {
 	struct mdss_mdp_ctl *ctl = arg;
@@ -286,6 +314,8 @@
 	complete_all(&ctx->pp_comp);
 
 	if (ctx->koff_cnt) {
+		atomic_inc(&ctx->pp_done_cnt);
+		schedule_work(&ctx->pp_done_work);
 		ctx->koff_cnt--;
 		if (ctx->koff_cnt) {
 			pr_err("%s: too many kickoffs=%d!\n", __func__,
@@ -301,6 +331,16 @@
 	spin_unlock(&ctx->clk_lock);
 }
 
+static void pingpong_done_work(struct work_struct *work)
+{
+	struct mdss_mdp_cmd_ctx *ctx =
+		container_of(work, typeof(*ctx), pp_done_work);
+
+	if (ctx->ctl)
+		while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0))
+			mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE);
+}
+
 static void clk_ctrl_work(struct work_struct *work)
 {
 	struct mdss_mdp_cmd_ctx *ctx =
@@ -374,7 +414,7 @@
 	return 0;
 }
 
-int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff)
 {
 	struct mdss_panel_data *pdata;
 	int ret = 0;
@@ -421,8 +461,10 @@
 			WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
 						rc, ctl->num);
 			rc = -EPERM;
-		} else
+			mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
+		} else {
 			rc = 0;
+		}
 	}
 
 	return rc;
@@ -471,7 +513,8 @@
 	/*
 	 * tx dcs command if had any
 	 */
-	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
+	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF,
+						(void *)&ctx->recovery);
 
 	mdss_mdp_cmd_clk_on(ctx);
 
@@ -499,6 +542,10 @@
 		pr_err("invalid ctx\n");
 		return -ENODEV;
 	}
+
+	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+		mdss_mdp_cmd_remove_vsync_handler(ctl, handle);
+
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (ctx->rdptr_enabled) {
 		INIT_COMPLETION(ctx->stop_comp);
@@ -516,10 +563,9 @@
 
 	mdss_mdp_cmd_clk_off(ctx);
 
-	ctx->panel_on = 0;
+	flush_work(&ctx->pp_done_work);
 
-	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
-		mdss_mdp_cmd_remove_vsync_handler(ctl, handle);
+	ctx->panel_on = 0;
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
 				   NULL, NULL);
@@ -585,8 +631,13 @@
 	spin_lock_init(&ctx->clk_lock);
 	mutex_init(&ctx->clk_mtx);
 	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+	INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
+	atomic_set(&ctx->pp_done_cnt, 0);
 	INIT_LIST_HEAD(&ctx->vsync_handlers);
 
+	ctx->recovery.fxn = mdss_mdp_cmd_underflow_recovery;
+	ctx->recovery.data = ctx;
+
 	pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
 				ctx, ctx->pp_num, mixer->num);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 728269d..7c79ceb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -21,6 +21,7 @@
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_panel.h"
 
 /* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
 #define VSYNC_TIMEOUT_US 100000
@@ -330,6 +331,7 @@
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_UNDER_RUN, ctl->intf_num,
 				   NULL, NULL);
 
+	mdss_mdp_ctl_reset(ctl);
 	ctx->ref_cnt--;
 	ctl->priv_data = NULL;
 
@@ -427,6 +429,9 @@
 		} else {
 			rc = 0;
 		}
+
+		mdss_mdp_ctl_notify(ctl,
+			rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
 	}
 
 	if (ctx->wait_pending) {
@@ -582,46 +587,52 @@
 	return 0;
 }
 
-int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
+	bool handoff)
 {
-	struct mdss_panel_data *pdata;
-	int ret = 0, off;
-	int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
-	int mdss_v2_intf_off = 0;
+	struct mdss_panel_data *pdata = ctl->panel_data;
+	int i, ret = 0;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
+	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_data_type *mdata = ctl->mdata;
 
-	off = 0;
-
-	pdata = ctl->panel_data;
-
-	pdata->panel_info.cont_splash_enabled = 0;
-
-	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
-				      NULL);
-	if (ret) {
-		pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n",
-					__func__);
-		return ret;
+	i = ctl->intf_num - MDSS_MDP_INTF0;
+	if (i < mdata->nintf) {
+		ctx = ((struct mdss_mdp_video_ctx *) mdata->video_intf) + i;
+		pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base);
+	} else {
+		pr_err("Invalid intf number: %d\n", ctl->intf_num);
+		ret = -EINVAL;
+		goto error;
 	}
 
-	mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
-	off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+	if (!handoff) {
+		ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
+					      NULL);
+		if (ret) {
+			pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n"
+				, __func__);
+			return ret;
+		}
 
-	if (mdss_mdp_rev >= MDSS_MDP_HW_REV_102)
-		mdss_v2_intf_off =  0xEC00;
+		mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
+		mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
 
-	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
-			mdss_v2_intf_off, 0);
-	/* wait for 1 VSYNC for the pipe to be unstaged */
-	msleep(20);
+		/* wait for 1 VSYNC for the pipe to be unstaged */
+		msleep(20);
+
+		ret = mdss_mdp_ctl_intf_event(ctl,
+			MDSS_EVENT_CONT_SPLASH_FINISH, NULL);
+	}
+
+error:
+	pdata->panel_info.cont_splash_enabled = 0;
 
 	/* Give back the reserved memory to the system */
 	memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size);
 	free_bootmem_late(mdp5_data->splash_mem_addr,
 				 mdp5_data->splash_mem_size);
 
-	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
-			NULL);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 2b07428..3929501 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -13,9 +13,9 @@
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
-#include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
+#include "mdss_panel.h"
 
 enum mdss_mdp_writeback_type {
 	MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
@@ -283,9 +283,9 @@
 	ctx->rot90 = !!(rot->flags & MDP_ROT_90);
 
 	if (ctx->bwc_mode || ctx->rot90)
-		format = mdss_mdp_get_rotator_dst_format(rot->format);
+		format = mdss_mdp_get_rotator_dst_format(rot->format, 1);
 	else
-		format = rot->format;
+		format = mdss_mdp_get_rotator_dst_format(rot->format, 0);
 
 	if (ctx->rot90) {
 		ctx->opmode |= BIT(5); /* ROT 90 */
@@ -421,10 +421,12 @@
 		NULL, NULL);
 
 	if (rc == 0) {
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
 		rc = -ENODEV;
 		WARN(1, "writeback kickoff timed out (%d) ctl=%d\n",
 						rc, ctl->num);
 	} else {
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_DONE);
 		rc = 0;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2d70556..c565d98 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -92,9 +92,9 @@
 	return 0;
 }
 
-static int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
-				      struct mdp_overlay *req,
-				      struct mdss_mdp_format_params *fmt)
+int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
+			       struct mdp_overlay *req,
+			       struct mdss_mdp_format_params *fmt)
 {
 	u32 xres, yres;
 	u32 min_src_size, min_dst_size;
@@ -250,84 +250,6 @@
 	return 0;
 }
 
-static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd,
-					  struct mdp_overlay *req)
-{
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	struct mdss_mdp_rotator_session *rot;
-	struct mdss_mdp_format_params *fmt;
-	int ret = 0;
-	u32 bwc_enabled;
-
-	pr_debug("rot ctl=%u req id=%x\n", mdp5_data->ctl->num, req->id);
-
-	fmt = mdss_mdp_get_format_params(req->src.format);
-	if (!fmt) {
-		pr_err("invalid rot format %d\n", req->src.format);
-		return -EINVAL;
-	}
-
-	ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
-	if (ret)
-		return ret;
-
-	if (req->id == MSMFB_NEW_REQUEST) {
-		rot = mdss_mdp_rotator_session_alloc();
-		rot->pid = current->tgid;
-		list_add(&rot->list, &mdp5_data->rot_proc_list);
-
-		if (!rot) {
-			pr_err("unable to allocate rotator session\n");
-			return -ENOMEM;
-		}
-	} else if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
-		rot = mdss_mdp_rotator_session_get(req->id);
-
-		if (!rot) {
-			pr_err("rotator session=%x not found\n", req->id);
-			return -ENODEV;
-		}
-	} else {
-		pr_err("invalid rotator session id=%x\n", req->id);
-		return -EINVAL;
-	}
-
-	/* keep only flags of interest to rotator */
-	rot->flags = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD |
-				   MDP_SECURE_OVERLAY_SESSION);
-
-	bwc_enabled = req->flags & MDP_BWC_EN;
-	if (bwc_enabled  &&  !mdp5_data->mdata->has_bwc) {
-		pr_err("BWC is not supported in MDP version %x\n",
-			mdp5_data->mdata->mdp_rev);
-		rot->bwc_mode = 0;
-	} else {
-		rot->bwc_mode = bwc_enabled ? 1 : 0;
-	}
-	rot->format = fmt->format;
-	rot->img_width = req->src.width;
-	rot->img_height = req->src.height;
-	rot->src_rect.x = req->src_rect.x;
-	rot->src_rect.y = req->src_rect.y;
-	rot->src_rect.w = req->src_rect.w;
-	rot->src_rect.h = req->src_rect.h;
-
-	if (req->flags & MDP_DEINTERLACE) {
-		rot->flags |= MDP_DEINTERLACE;
-		rot->src_rect.h /= 2;
-	}
-
-	ret = mdss_mdp_rotator_setup(rot);
-	if (ret == 0) {
-		req->id = rot->session_id;
-	} else {
-		pr_err("Unable to setup rotator session\n");
-		mdss_mdp_rotator_release(rot);
-	}
-
-	return ret;
-}
-
 static int __mdp_pipe_tune_perf(struct mdss_mdp_pipe *pipe)
 {
 	struct mdss_data_type *mdata = pipe->mixer->ctl->mdata;
@@ -415,7 +337,7 @@
 
 	if (req->flags & (MDP_SOURCE_ROTATED_90 | MDP_BWC_EN))
 		req->src.format =
-			mdss_mdp_get_rotator_dst_format(req->src.format);
+			mdss_mdp_get_rotator_dst_format(req->src.format, 1);
 
 	fmt = mdss_mdp_get_format_params(req->src.format);
 	if (!fmt) {
@@ -670,7 +592,7 @@
 	}
 
 	if (req->flags & MDSS_MDP_ROT_ONLY) {
-		ret = mdss_mdp_overlay_rotator_setup(mfd, req);
+		ret = mdss_mdp_rotator_setup(mfd, req);
 	} else if (req->src.format == MDP_RGB_BORDERFILL) {
 		req->id = BORDERFILL_NDX;
 	} else {
@@ -689,7 +611,7 @@
 	return ret;
 }
 
-static inline int mdss_mdp_overlay_get_buf(struct msm_fb_data_type *mfd,
+int mdss_mdp_overlay_get_buf(struct msm_fb_data_type *mfd,
 					   struct mdss_mdp_data *data,
 					   struct msmfb_data *planes,
 					   int num_planes,
@@ -719,7 +641,7 @@
 	return rc;
 }
 
-static inline int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
+int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
 {
 	int i;
 	for (i = 0; i < data->num_planes && data->p[i].len; i++)
@@ -798,13 +720,64 @@
 		mdss_mdp_pipe_destroy(pipe);
 }
 
+static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd,
+	u32 type)
+{
+	u32 i, npipes;
+	struct mdss_mdp_pipe *pipes;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+
+	switch (type) {
+	case MDSS_MDP_PIPE_TYPE_VIG:
+		pipes = mdata->vig_pipes;
+		npipes = mdata->nvig_pipes;
+		break;
+	case MDSS_MDP_PIPE_TYPE_RGB:
+		pipes = mdata->rgb_pipes;
+		npipes = mdata->nrgb_pipes;
+		break;
+	case MDSS_MDP_PIPE_TYPE_DMA:
+		pipes = mdata->dma_pipes;
+		npipes = mdata->ndma_pipes;
+		break;
+	default:
+		return;
+	}
+
+	for (i = 0; i < npipes; i++) {
+		pipe = &pipes[i];
+		if (pipe->is_handed_off) {
+			pr_debug("Unmapping handed off pipe %d\n", pipe->num);
+			list_add(&pipe->cleanup_list,
+				&mdp5_data->pipes_cleanup);
+			mdss_mdp_mixer_pipe_unstage(pipe);
+			pipe->is_handed_off = false;
+		}
+	}
+}
+
+/**
+ * mdss_mdp_overlay_start() - Programs the MDP control data path to hardware
+ * @mfd: Msm frame buffer structure associated with fb device.
+ *
+ * Program the MDP hardware with the control settings for the framebuffer
+ * device. In addition to this, this function also handles the transition
+ * from the the splash screen to the android boot animation when the
+ * continuous splash screen feature is enabled.
+ */
 static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
 {
 	int rc;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
 
-	if (mdp5_data->ctl->power_on)
+	if (ctl->power_on) {
+		if (!mdp5_data->mdata->batfet)
+			mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
 		return 0;
+	}
 
 	pr_debug("starting fb%d overlay\n", mfd->index);
 
@@ -814,24 +787,84 @@
 		return rc;
 	}
 
-	if (mfd->panel_info->cont_splash_enabled) {
-		mdss_mdp_ctl_splash_finish(mdp5_data->ctl);
-		mdss_mdp_footswitch_ctrl_splash(0);
-	}
-
+	/*
+	 * We need to do hw init before any hw programming.
+	 * Also, hw init involves programming the VBIF registers which
+	 * should be done only after attaching IOMMU which in turn would call
+	 * in to TZ to restore security configs on the VBIF registers.
+	 * This is not needed when continuous splash screen is enabled since
+	 * we would have called in to TZ to restore security configs from LK.
+	 */
 	if (!is_mdss_iommu_attached()) {
-		mdss_iommu_attach(mdss_res);
+		if (!mfd->panel_info->cont_splash_enabled)
+			mdss_iommu_attach(mdss_res);
 		mdss_hw_init(mdss_res);
 	}
 
-	rc = mdss_mdp_ctl_start(mdp5_data->ctl);
+	rc = mdss_mdp_ctl_start(ctl);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
-	} else {
-		pr_err("overlay start failed.\n");
-		mdss_mdp_ctl_destroy(mdp5_data->ctl);
-		mdp5_data->ctl = NULL;
 
+		mdss_mdp_ctl_notifier_register(mdp5_data->ctl,
+				&mfd->mdp_sync_pt_data.notifier);
+	} else {
+		pr_err("mdp ctl start failed.\n");
+		goto error;
+	}
+
+	if (mfd->panel_info->cont_splash_enabled) {
+		if (mdp5_data->handoff) {
+			/*
+			 * Set up border-fill on the handed off pipes.
+			 * This is needed to ensure that there are no memory
+			 * accesses prior to attaching iommu during continuous
+			 * splash screen case. However, for command mode
+			 * displays, this is not necessary since the panels can
+			 * refresh from their internal memory if no data is sent
+			 * out on the dsi lanes.
+			 */
+			if (ctl && ctl->is_video_mode) {
+				rc = mdss_mdp_display_commit(ctl, NULL);
+				if (!IS_ERR_VALUE(rc)) {
+					mdss_mdp_display_wait4comp(ctl);
+				} else {
+					/*
+					 * Since border-fill setup failed, we
+					 * need to ensure that we turn off the
+					 * MDP timing generator before attaching
+					 * iommu
+					 */
+					pr_err("failed to set BF at handoff\n");
+					mdp5_data->handoff = false;
+					rc = 0;
+				}
+			}
+
+			/* Add all the handed off pipes to the cleanup list */
+			__mdss_mdp_handoff_cleanup_pipes(mfd,
+				MDSS_MDP_PIPE_TYPE_RGB);
+			__mdss_mdp_handoff_cleanup_pipes(mfd,
+				MDSS_MDP_PIPE_TYPE_VIG);
+			__mdss_mdp_handoff_cleanup_pipes(mfd,
+				MDSS_MDP_PIPE_TYPE_DMA);
+		}
+		rc = mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff);
+		/*
+		 * Remove the vote for footswitch even if above function
+		 * returned error
+		 */
+		mdss_mdp_footswitch_ctrl_splash(0);
+		if (rc)
+			goto error;
+
+		if (!is_mdss_iommu_attached())
+			mdss_iommu_attach(mdss_res);
+	}
+
+error:
+	if (rc) {
+		mdss_mdp_ctl_destroy(ctl);
+		mdp5_data->ctl = NULL;
 		pm_runtime_put(&mfd->pdev->dev);
 	}
 
@@ -858,7 +891,7 @@
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_ctl *tmp;
-	int ret;
+	int ret = 0;
 	int sd_in_pipe = 0;
 
 	if (ctl->shared_lock)
@@ -867,14 +900,6 @@
 	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
 
-	ret = mdss_mdp_display_wait4pingpong(mdp5_data->ctl);
-	if (ret) {
-		mutex_unlock(&mfd->lock);
-		mutex_unlock(&mdp5_data->ov_lock);
-		if (ctl->shared_lock)
-			mutex_unlock(ctl->shared_lock);
-		return ret;
-	}
 	/*
 	 * check if there is a secure display session
 	 */
@@ -894,6 +919,9 @@
 			mdp5_data->sd_enabled = 0;
 	}
 
+	mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_BEGIN);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
 	if (data)
 		mdss_mdp_set_roi(ctl, data);
 
@@ -988,6 +1016,8 @@
 	mdss_fb_update_notify_update(mfd);
 commit_fail:
 	mdss_mdp_overlay_cleanup(mfd);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_FLUSHED);
 
 	mutex_unlock(&mdp5_data->ov_lock);
 	if (ctl->shared_lock)
@@ -1059,17 +1089,7 @@
 	pr_debug("unset ndx=%x\n", ndx);
 
 	if (ndx & MDSS_MDP_ROT_SESSION_MASK) {
-		struct mdss_mdp_rotator_session *rot;
-		rot = mdss_mdp_rotator_session_get(ndx);
-		if (rot) {
-			mdss_mdp_overlay_free_buf(&rot->src_buf);
-			mdss_mdp_overlay_free_buf(&rot->dst_buf);
-
-			rot->pid = 0;
-			if (!list_empty(&rot->list))
-				list_del_init(&rot->list);
-			ret = mdss_mdp_rotator_release(rot);
-		}
+		ret = mdss_mdp_rotator_unset(ndx);
 	} else {
 		ret = mdss_mdp_overlay_release(mfd, ndx);
 	}
@@ -1150,50 +1170,6 @@
 	return ret;
 }
 
-static int mdss_mdp_overlay_rotate(struct msm_fb_data_type *mfd,
-				   struct msmfb_overlay_data *req)
-{
-	struct mdss_mdp_rotator_session *rot;
-	int ret;
-	u32 flgs;
-
-	rot = mdss_mdp_rotator_session_get(req->id);
-	if (!rot) {
-		pr_err("invalid session id=%x\n", req->id);
-		return -ENOENT;
-	}
-
-	flgs = rot->flags & MDP_SECURE_OVERLAY_SESSION;
-
-	ret = mdss_mdp_rotator_busy_wait_ex(rot);
-	if (ret) {
-		pr_err("rotator busy wait error\n");
-		return ret;
-	}
-
-	mdss_mdp_overlay_free_buf(&rot->src_buf);
-	ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
-	if (ret) {
-		pr_err("src_data pmem error\n");
-		return ret;
-	}
-
-	mdss_mdp_overlay_free_buf(&rot->dst_buf);
-	ret = mdss_mdp_overlay_get_buf(mfd, &rot->dst_buf,
-			&req->dst_data, 1, flgs);
-	if (ret) {
-		pr_err("dst_data pmem error\n");
-		goto dst_buf_fail;
-	}
-
-	ret = mdss_mdp_rotator_queue(rot);
-	if (ret)
-		pr_err("rotator queue error session id=%x\n", req->id);
-
-dst_buf_fail:
-	return ret;
-}
-
 static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
 				  struct msmfb_overlay_data *req)
 {
@@ -1289,7 +1265,7 @@
 	if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
 		mdss_mdp_overlay_force_dma_cleanup(mfd_to_mdata(mfd));
 
-		ret = mdss_mdp_overlay_rotate(mfd, req);
+		ret = mdss_mdp_rotator_play(mfd, req);
 	} else if (req->id == BORDERFILL_NDX) {
 		pr_debug("borderfill enable\n");
 		mdp5_data->borderfill_enable = true;
@@ -2227,7 +2203,6 @@
 	case MSMFB_OVERLAY_COMMIT:
 		mdss_fb_wait_for_fence(&(mfd->mdp_sync_pt_data));
 		ret = mfd->mdp.kickoff_fnc(mfd, NULL);
-		mdss_fb_signal_timeline(&(mfd->mdp_sync_pt_data));
 		break;
 	case MSMFB_METADATA_SET:
 		ret = copy_from_user(&metadata, argp, sizeof(metadata));
@@ -2252,10 +2227,66 @@
 	return ret;
 }
 
+/**
+ * __mdss_mdp_overlay_ctl_init - Helper function to intialize control structure
+ * @mfd: msm frame buffer data structure associated with the fb device.
+ *
+ * Helper function that allocates and initializes the mdp control structure
+ * for a frame buffer device. Whenver applicable, this function will also setup
+ * the control for the split display path as well.
+ *
+ * Return: pointer to the newly allocated control structure.
+ */
+static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init(
+	struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_panel_data *pdata;
+
+	if (!mfd)
+		return ERR_PTR(-EINVAL);
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		rc = -ENODEV;
+		goto error;
+	}
+
+	ctl = mdss_mdp_ctl_init(pdata, mfd);
+	if (IS_ERR_OR_NULL(ctl)) {
+		pr_err("Unable to initialize ctl for fb%d\n",
+			mfd->index);
+		rc = PTR_ERR(ctl);
+		goto error;
+	}
+	ctl->vsync_handler.vsync_handler =
+					mdss_mdp_overlay_handle_vsync;
+	ctl->vsync_handler.cmd_post_flush = false;
+
+	if (mfd->split_display && pdata->next) {
+		/* enable split display */
+		rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next);
+		if (rc) {
+			mdss_mdp_ctl_destroy(ctl);
+			goto error;
+		}
+	}
+
+error:
+	if (rc)
+		return ERR_PTR(rc);
+	else
+		return ctl;
+}
+
 static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
 {
 	int rc;
 	struct mdss_overlay_private *mdp5_data;
+	struct mdss_mdp_ctl *ctl = NULL;
+
 	if (!mfd)
 		return -ENODEV;
 
@@ -2267,33 +2298,9 @@
 		return -EINVAL;
 
 	if (!mdp5_data->ctl) {
-		struct mdss_mdp_ctl *ctl;
-		struct mdss_panel_data *pdata;
-
-		pdata = dev_get_platdata(&mfd->pdev->dev);
-		if (!pdata) {
-			pr_err("no panel connected for fb%d\n", mfd->index);
-			return -ENODEV;
-		}
-
-		ctl = mdss_mdp_ctl_init(pdata, mfd);
-		if (IS_ERR_OR_NULL(ctl)) {
-			pr_err("Unable to initialize ctl for fb%d\n",
-				mfd->index);
+		ctl = __mdss_mdp_overlay_ctl_init(mfd);
+		if (IS_ERR_OR_NULL(ctl))
 			return PTR_ERR(ctl);
-		}
-		ctl->vsync_handler.vsync_handler =
-						mdss_mdp_overlay_handle_vsync;
-		ctl->vsync_handler.cmd_post_flush = false;
-
-		if (mfd->split_display && pdata->next) {
-			/* enable split display */
-			rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next);
-			if (rc) {
-				mdss_mdp_ctl_destroy(ctl);
-				return rc;
-			}
-		}
 		mdp5_data->ctl = ctl;
 	}
 
@@ -2361,6 +2368,8 @@
 	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
 	if (rc == 0) {
 		__mdss_mdp_overlay_free_list_purge(mfd);
+		mdss_mdp_ctl_notifier_unregister(mdp5_data->ctl,
+				&mfd->mdp_sync_pt_data.notifier);
 
 		if (!mfd->ref_cnt) {
 			mdp5_data->borderfill_enable = false;
@@ -2392,6 +2401,96 @@
 	return 0;
 }
 
+/**
+ * mdss_mdp_overlay_handoff() - Read MDP registers to handoff an active ctl path
+ * @mfd: Msm frame buffer structure associated with the fb device.
+ *
+ * This function populates the MDP software structures with the current state of
+ * the MDP hardware to handoff any active control path for the framebuffer
+ * device. This is needed to identify any ctl, mixers and pipes being set up by
+ * the bootloader to display the splash screen when the continuous splash screen
+ * feature is enabled in kernel.
+ */
+static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int i, j;
+	u32 reg;
+	struct mdss_mdp_pipe *pipe = NULL;
+	struct mdss_mdp_ctl *ctl = NULL;
+
+	if (!mdp5_data->ctl) {
+		ctl = __mdss_mdp_overlay_ctl_init(mfd);
+		if (IS_ERR_OR_NULL(ctl)) {
+			rc = PTR_ERR(ctl);
+			goto error;
+		}
+		mdp5_data->ctl = ctl;
+	}
+
+	rc = mdss_mdp_ctl_setup(ctl);
+	if (rc)
+		goto error;
+
+	ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
+	pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
+
+	for (i = 0; i < mdata->nmixers_intf; i++) {
+		reg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i));
+		pr_debug("for lm%d reg = 0x%09x\n", i, reg);
+		for (j = MDSS_MDP_SSPP_VIG0; j < MDSS_MDP_MAX_SSPP; j++) {
+			u32 cfg = j * 3;
+			if ((j == MDSS_MDP_SSPP_VIG3) ||
+				(j == MDSS_MDP_SSPP_RGB3)) {
+				/* Add 2 to account for Cursor & Border bits */
+				cfg += 2;
+			}
+			if (reg & (0x7 << cfg)) {
+				pr_debug("Pipe %d staged\n", j);
+				pipe = mdss_mdp_pipe_search(mdata, BIT(j));
+				if (!pipe) {
+					pr_warn("Invalid pipe %d staged\n", j);
+					continue;
+				}
+
+				rc = mdss_mdp_pipe_handoff(pipe);
+				if (rc) {
+					pr_err("Failed to handoff pipe num %d\n"
+						, pipe->num);
+					goto error;
+				}
+
+				rc = mdss_mdp_mixer_handoff(ctl, i, pipe);
+				if (rc) {
+					pr_err("failed to handoff mixer num %d\n"
+						, i);
+					goto error;
+				}
+			}
+		}
+	}
+
+	rc = mdss_mdp_smp_handoff(mdata);
+	if (rc)
+		pr_err("Failed to handoff smps\n");
+
+	mdp5_data->handoff = true;
+
+error:
+	if (rc && ctl) {
+		__mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB);
+		__mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG);
+		__mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA);
+		mdss_mdp_ctl_destroy(ctl);
+		mdp5_data->ctl = NULL;
+		mdp5_data->handoff = false;
+	}
+
+	return rc;
+}
+
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
@@ -2458,6 +2557,7 @@
 			goto init_fail;
 		}
 	}
+	mfd->mdp_sync_pt_data.async_wait_fences = true;
 
 	pm_runtime_set_suspended(&mfd->pdev->dev);
 	pm_runtime_enable(&mfd->pdev->dev);
@@ -2469,6 +2569,21 @@
 	if (!mdp5_data->cpu_pm_hdl)
 		pr_warn("%s: unable to add event timer\n", __func__);
 
+	if (mfd->panel_info->cont_splash_enabled) {
+		rc = mdss_mdp_overlay_handoff(mfd);
+		if (rc) {
+			/*
+			 * Even though handoff failed, it is not fatal.
+			 * MDP can continue, just that we would have a longer
+			 * delay in transitioning from splash screen to boot
+			 * animation
+			 */
+			pr_warn("Overlay handoff failed for fb%d. rc=%d\n",
+				mfd->index, rc);
+			rc = 0;
+		}
+	}
+
 	return rc;
 init_fail:
 	kfree(mdp5_data);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c18fd9b..779f74c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -27,10 +27,10 @@
 
 static DEFINE_MUTEX(mdss_mdp_sspp_lock);
 static DEFINE_MUTEX(mdss_mdp_smp_lock);
-static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
 
 static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
-static int __mdss_mdp_pipe_smp_mmb_is_empty(unsigned long *smp);
+static struct mdss_mdp_pipe *mdss_mdp_pipe_search_by_client_id(
+	struct mdss_data_type *mdata, int client_id);
 
 static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
 				       u32 reg, u32 val)
@@ -43,21 +43,29 @@
 	return readl_relaxed(pipe->base + reg);
 }
 
-static u32 mdss_mdp_smp_mmb_reserve(unsigned long *existing,
-	unsigned long *reserve, size_t n)
+static u32 mdss_mdp_smp_mmb_reserve(struct mdss_mdp_pipe_smp_map *smp_map,
+	size_t n)
 {
 	u32 i, mmb;
+	u32 fixed_cnt = bitmap_weight(smp_map->fixed, SMP_MB_CNT);
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	if (n <= fixed_cnt)
+		return fixed_cnt;
+	else
+		n -= fixed_cnt;
 
 	/* reserve more blocks if needed, but can't free mmb at this point */
-	for (i = bitmap_weight(existing, SMP_MB_CNT); i < n; i++) {
-		if (bitmap_full(mdss_mdp_smp_mmb_pool, SMP_MB_CNT))
+	for (i = bitmap_weight(smp_map->allocated, SMP_MB_CNT); i < n; i++) {
+		if (bitmap_full(mdata->mmb_alloc_map, SMP_MB_CNT))
 			break;
 
-		mmb = find_first_zero_bit(mdss_mdp_smp_mmb_pool, SMP_MB_CNT);
-		set_bit(mmb, reserve);
-		set_bit(mmb, mdss_mdp_smp_mmb_pool);
+		mmb = find_first_zero_bit(mdata->mmb_alloc_map, SMP_MB_CNT);
+		set_bit(mmb, smp_map->reserved);
+		set_bit(mmb, mdata->mmb_alloc_map);
 	}
-	return i;
+
+	return i + fixed_cnt;
 }
 
 static int mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
@@ -86,20 +94,17 @@
 
 static void mdss_mdp_smp_mmb_free(unsigned long *smp, bool write)
 {
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
 	if (!bitmap_empty(smp, SMP_MB_CNT)) {
 		if (write)
 			mdss_mdp_smp_mmb_set(0, smp);
-		bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
+		bitmap_andnot(mdata->mmb_alloc_map, mdata->mmb_alloc_map,
 			      smp, SMP_MB_CNT);
 		bitmap_zero(smp, SMP_MB_CNT);
 	}
 }
 
-static int __mdss_mdp_pipe_smp_mmb_is_empty(unsigned long *smp)
-{
-	return bitmap_weight(smp, SMP_MB_CNT) == 0;
-}
-
 static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
 {
 	u32 fetch_size, val, wm[3];
@@ -229,8 +234,8 @@
 
 		pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
 				num_blks, pipe->num, i);
-		reserved = mdss_mdp_smp_mmb_reserve(pipe->smp_map[i].allocated,
-			pipe->smp_map[i].reserved, num_blks);
+		reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp_map[i],
+			num_blks);
 		if (reserved < num_blks)
 			break;
 	}
@@ -246,7 +251,21 @@
 
 	return rc;
 }
-
+/*
+ * mdss_mdp_smp_alloc() -- set smp mmb and and wm levels for a staged pipe
+ * @pipe: pointer to a pipe
+ *
+ * Function amends reserved smp mmbs to allocated bitmap and ties respective
+ * mmbs to their pipe fetch_ids. Based on the number of total allocated mmbs
+ * for a staged pipe, it also sets the watermark levels (wm).
+ *
+ * This function will be called on every commit where pipe params might not
+ * have changed. In such cases, we need to ensure that wm levels are not
+ * wiped out. Also in some rare situations hw might have reset and wiped out
+ * smp mmb programming but new smp reservation is not done. In such cases we
+ * need to ensure that for a staged pipes, mmbs are set properly based on
+ * allocated bitmap.
+ */
 static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
 {
 	int i;
@@ -254,8 +273,14 @@
 
 	mutex_lock(&mdss_mdp_smp_lock);
 	for (i = 0; i < MAX_PLANES; i++) {
-		if (__mdss_mdp_pipe_smp_mmb_is_empty(pipe->smp_map[i].reserved))
+		cnt += bitmap_weight(pipe->smp_map[i].fixed, SMP_MB_CNT);
+
+		if (bitmap_empty(pipe->smp_map[i].reserved, SMP_MB_CNT)) {
+			cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i,
+				pipe->smp_map[i].allocated);
 			continue;
+		}
+
 		mdss_mdp_smp_mmb_amend(pipe->smp_map[i].allocated,
 			pipe->smp_map[i].reserved);
 		cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i,
@@ -284,6 +309,80 @@
 	return 0;
 }
 
+/**
+ * mdss_mdp_smp_handoff() - Handoff SMP MMBs in use by staged pipes
+ * @mdata: pointer to the global mdss data structure.
+ *
+ * Iterate through the list of all SMP MMBs and check to see if any
+ * of them are assigned to a pipe being marked as being handed-off.
+ * If so, update the corresponding software allocation map to reflect
+ * this.
+ *
+ * This function would typically be called during MDP probe for the case
+ * when certain pipes might be programmed in the bootloader to display
+ * the splash screen.
+ */
+int mdss_mdp_smp_handoff(struct mdss_data_type *mdata)
+{
+	int rc = 0;
+	int i, client_id, prev_id = 0;
+	u32 off, s, data;
+	struct mdss_mdp_pipe *pipe = NULL;
+
+	/*
+	 * figure out what SMP MMBs are allocated for each of the pipes
+	 * that need to be handed off.
+	 */
+	for (i = 0; i < SMP_MB_CNT; i++) {
+		off = (i / 3) * 4;
+		s = (i % 3) * 8;
+		data = MDSS_MDP_REG_READ(MDSS_MDP_REG_SMP_ALLOC_W0 + off);
+		client_id = (data >> s) & 0xFF;
+		if (test_bit(i, mdata->mmb_alloc_map)) {
+			/*
+			 * Certain pipes may have a dedicated set of
+			 * SMP MMBs statically allocated to them. In
+			 * such cases, we do not need to do anything
+			 * here.
+			 */
+			pr_debug("smp mmb %d already assigned to pipe %d (client_id %d)"
+				, i, pipe->num, client_id);
+			continue;
+		}
+
+		if (client_id) {
+			if (client_id != prev_id) {
+				pipe = mdss_mdp_pipe_search_by_client_id(mdata,
+					client_id);
+				prev_id = client_id;
+			}
+
+			if (!pipe) {
+				pr_warn("Invalid client id %d for SMP MMB %d\n",
+					client_id, i);
+				continue;
+			}
+
+			if (!pipe->is_handed_off) {
+				pr_warn("SMP MMB %d assigned to a pipe not marked for handoff (client id %d)"
+					, i, client_id);
+				continue;
+			}
+
+			/*
+			 * Assume that the source format only has
+			 * one plane
+			 */
+			pr_debug("Assigning smp mmb %d to pipe %d (client_id %d)\n"
+				, i, pipe->num, client_id);
+			set_bit(i, pipe->smp_map[0].allocated);
+			set_bit(i, mdata->mmb_alloc_map);
+		}
+	}
+
+	return rc;
+}
+
 void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe)
 {
 	int tmp;
@@ -427,6 +526,29 @@
 	return pipe;
 }
 
+static struct mdss_mdp_pipe *mdss_mdp_pipe_search_by_client_id(
+	struct mdss_data_type *mdata, int client_id)
+{
+	u32 i;
+
+	for (i = 0; i < mdata->nrgb_pipes; i++) {
+		if (mdata->rgb_pipes[i].ftch_id == client_id)
+			return &mdata->rgb_pipes[i];
+	}
+
+	for (i = 0; i < mdata->nvig_pipes; i++) {
+		if (mdata->vig_pipes[i].ftch_id == client_id)
+			return &mdata->vig_pipes[i];
+	}
+
+	for (i = 0; i < mdata->ndma_pipes; i++) {
+		if (mdata->dma_pipes[i].ftch_id == client_id)
+			return &mdata->dma_pipes[i];
+	}
+
+	return NULL;
+}
+
 struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
 						  u32 ndx)
 {
@@ -481,6 +603,67 @@
 
 }
 
+/**
+ * mdss_mdp_pipe_handoff() - Handoff staged pipes during bootup
+ * @pipe: pointer to the pipe to be handed-off
+ *
+ * Populate the software structures for the pipe based on the current
+ * configuration of the hardware pipe by the reading the appropriate MDP
+ * registers.
+ *
+ * This function would typically be called during MDP probe for the case
+ * when certain pipes might be programmed in the bootloader to display
+ * the splash screen.
+ */
+int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe)
+{
+	int rc = 0;
+	u32 src_fmt, reg = 0, bpp = 0;
+
+	/*
+	 * todo: for now, only reading pipe src and dest size details
+	 * from the registers. This is needed for appropriately
+	 * calculating perf metrics for the handed off pipes.
+	 * We may need to parse some more details at a later date.
+	 */
+	reg = mdss_mdp_pipe_read(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE);
+	pipe->src.h = reg >> 16;
+	pipe->src.w = reg & 0xFFFF;
+	reg = mdss_mdp_pipe_read(pipe, MDSS_MDP_REG_SSPP_OUT_SIZE);
+	pipe->dst.h = reg >> 16;
+	pipe->dst.w = reg & 0xFFFF;
+
+	/* Assume that the source format is RGB */
+	reg = mdss_mdp_pipe_read(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT);
+	bpp = ((reg >> 9) & 0x3) + 1;
+	switch (bpp) {
+	case 4:
+		src_fmt = MDP_RGBA_8888;
+		break;
+	case 3:
+		src_fmt = MDP_RGB_888;
+		break;
+	case 2:
+		src_fmt = MDP_RGB_565;
+		break;
+	default:
+		pr_err("Invalid bpp=%d found\n", bpp);
+		rc = -EINVAL;
+		goto error;
+	}
+	pipe->src_fmt = mdss_mdp_get_format_params(src_fmt);
+
+	pr_debug("Pipe settings: src.h=%d src.w=%d dst.h=%d dst.w=%d bpp=%d\n"
+		, pipe->src.h, pipe->src.w, pipe->dst.h, pipe->dst.w,
+		pipe->src_fmt->bpp);
+
+	pipe->is_handed_off = true;
+	atomic_inc(&pipe->ref_cnt);
+
+error:
+	return rc;
+}
+
 void mdss_mdp_crop_rect(struct mdss_mdp_img_rect *src_rect,
 	struct mdss_mdp_img_rect *dst_rect,
 	const struct mdss_mdp_img_rect *sci_rect)
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 563a4a6..b31f6c1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -711,7 +711,7 @@
 			if (src_h <= pipe->dst.h) {
 				scale_config |= /* G/Y, A */
 					(filter_mode << 10) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+					(MDSS_MDP_SCALE_FILTER_BIL << 18);
 			} else
 				scale_config |= /* G/Y, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
@@ -730,7 +730,7 @@
 			if (src_h <= pipe->dst.h)
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_BIL << 10) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+					(MDSS_MDP_SCALE_FILTER_BIL << 18);
 			else
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
@@ -764,7 +764,7 @@
 			if (src_w <= pipe->dst.w) {
 				scale_config |= /* G/Y, A */
 					(filter_mode << 8) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+					(MDSS_MDP_SCALE_FILTER_BIL << 16);
 			} else
 				scale_config |= /* G/Y, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
@@ -783,7 +783,7 @@
 			if (src_w <= pipe->dst.w)
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_BIL << 8) |
-					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+					(MDSS_MDP_SCALE_FILTER_BIL << 16);
 			else
 				scale_config |= /* RGB, A */
 					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
@@ -1213,7 +1213,7 @@
 			pp_ad_cfg_write(ad);
 		if (PP_AD_STATE_INIT & ad->state)
 			pp_ad_init_write(ad);
-		if (PP_AD_STATE_DATA & ad->state) {
+		if ((PP_AD_STATE_DATA & ad->state) && (ad->sts & PP_STS_ENABLE)) {
 			bl = ad->bl_mfd->bl_level;
 			ad->last_bl = bl;
 			if (ad->state & PP_AD_STATE_BL_LIN) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 44734f8..1d172f3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -37,12 +37,11 @@
 static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
 			struct mdss_mdp_rotator_session *rot);
 
-struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
+static struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
 {
 	struct mdss_mdp_rotator_session *rot;
 	int i;
 
-	mutex_lock(&rotator_lock);
 	for (i = 0; i < MAX_ROTATOR_SESSIONS; i++) {
 		rot = &rotator_session[i];
 		if (rot->ref_cnt == 0) {
@@ -52,16 +51,15 @@
 			break;
 		}
 	}
-	mutex_unlock(&rotator_lock);
 	if (i == MAX_ROTATOR_SESSIONS) {
 		pr_err("max rotator sessions reached\n");
 		return NULL;
 	}
-
 	return rot;
 }
 
-struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id)
+static inline struct mdss_mdp_rotator_session
+*mdss_mdp_rotator_session_get(u32 session_id)
 {
 	struct mdss_mdp_rotator_session *rot;
 	u32 ndx;
@@ -113,16 +111,15 @@
 
 static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot)
 {
-	struct mdss_mdp_pipe *rot_pipe = NULL;
-	struct mdss_mdp_ctl *ctl = NULL;
 
-	rot_pipe = rot->pipe;
-	if (!rot_pipe)
-		return -ENODEV;
-
-	ctl = rot_pipe->mixer->ctl;
 	mutex_lock(&rot->lock);
+	if (!rot->pipe || !rot->pipe->mixer || !rot->pipe->mixer->ctl) {
+		mutex_unlock(&rot->lock);
+		return -ENODEV;
+	}
+
 	if (rot->busy) {
+		struct mdss_mdp_ctl *ctl = rot->pipe->mixer->ctl;
 		mdss_mdp_display_wait4comp(ctl);
 		rot->busy = false;
 		if (ctl->shared_lock)
@@ -276,17 +273,20 @@
 	int ret;
 
 	rot = container_of(work, struct mdss_mdp_rotator_session, commit_work);
-	ret = mdss_mdp_rotator_queue_helper(rot);
 
-	if (ret) {
+	mutex_lock(&rotator_lock);
+	ret = mdss_mdp_rotator_queue_helper(rot);
+	if (ret)
 		pr_err("rotator queue failed\n");
-		return;
+
+	if (rot->rot_sync_pt_data) {
+		atomic_inc(&rot->rot_sync_pt_data->commit_cnt);
+		mdss_fb_signal_timeline(rot->rot_sync_pt_data);
+	} else {
+		pr_err("rot_sync_pt_data is NULL\n");
 	}
 
-	if (rot->rot_sync_pt_data)
-		mdss_fb_signal_timeline(rot->rot_sync_pt_data);
-	else
-		pr_err("rot_sync_pt_data is NULL\n");
+	mutex_unlock(&rotator_lock);
 }
 
 static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
@@ -318,7 +318,7 @@
 	return sync_pt_data;
 }
 
-int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot)
+static int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot)
 {
 
 	struct mdss_mdp_rotator_session *tmp;
@@ -337,20 +337,12 @@
 	int ret;
 	struct mdss_mdp_rotator_session *tmp;
 
-	ret = mutex_lock_interruptible(&rotator_lock);
-	if (ret) {
-		pr_err("mutex lock on rotator_lock failed\n");
-		return ret;
-	}
-
 	pr_debug("rotator session=%x start\n", rot->session_id);
 
 	for (ret = 0, tmp = rot; ret == 0 && tmp; tmp = tmp->next)
 		ret = mdss_mdp_rotator_queue_sub(tmp,
 				&rot->src_buf, &rot->dst_buf);
 
-	mutex_unlock(&rotator_lock);
-
 	if (ret) {
 		pr_err("rotation failed %d for rot=%d\n", ret, rot->session_id);
 		return ret;
@@ -362,7 +354,7 @@
 	return ret;
 }
 
-int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot)
+static int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot)
 {
 	int ret = 0;
 
@@ -376,10 +368,80 @@
 	return ret;
 }
 
-int mdss_mdp_rotator_setup(struct mdss_mdp_rotator_session *rot)
+int mdss_mdp_rotator_setup(struct msm_fb_data_type *mfd,
+			   struct mdp_overlay *req)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_rotator_session *rot = NULL;
+	struct mdss_mdp_format_params *fmt;
+	u32 bwc_enabled;
+	int ret = 0;
+
+	mutex_lock(&rotator_lock);
+
+	fmt = mdss_mdp_get_format_params(req->src.format);
+	if (!fmt) {
+		pr_err("invalid rot format %d\n", req->src.format);
+		ret = -EINVAL;
+		goto rot_err;
+	}
+
+	ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
+	if (ret)
+		goto rot_err;
+
+	if (req->id == MSMFB_NEW_REQUEST) {
+		rot = mdss_mdp_rotator_session_alloc();
+		rot->pid = current->tgid;
+		list_add(&rot->list, &mdp5_data->rot_proc_list);
+
+		if (!rot) {
+			pr_err("unable to allocate rotator session\n");
+			ret = -ENOMEM;
+			goto rot_err;
+		}
+	} else if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
+		rot = mdss_mdp_rotator_session_get(req->id);
+
+		if (!rot) {
+			pr_err("rotator session=%x not found\n", req->id);
+			ret = -ENODEV;
+			goto rot_err;
+		}
+	} else {
+		pr_err("invalid rotator session id=%x\n", req->id);
+		ret = -EINVAL;
+		goto rot_err;
+	}
+
+	/* keep only flags of interest to rotator */
+	rot->flags = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD |
+				   MDP_SECURE_OVERLAY_SESSION);
+
+	bwc_enabled = req->flags & MDP_BWC_EN;
+	if (bwc_enabled  &&  !mdp5_data->mdata->has_bwc) {
+		pr_err("BWC is not supported in MDP version %x\n",
+			mdp5_data->mdata->mdp_rev);
+		rot->bwc_mode = 0;
+	} else {
+		rot->bwc_mode = bwc_enabled ? 1 : 0;
+	}
+	rot->format = fmt->format;
+	rot->img_width = req->src.width;
+	rot->img_height = req->src.height;
+	rot->src_rect.x = req->src_rect.x;
+	rot->src_rect.y = req->src_rect.y;
+	rot->src_rect.w = req->src_rect.w;
+	rot->src_rect.h = req->src_rect.h;
+
+	if (req->flags & MDP_DEINTERLACE) {
+		rot->flags |= MDP_DEINTERLACE;
+		rot->src_rect.h /= 2;
+		rot->src_rect.y = DIV_ROUND_UP(rot->src_rect.y, 2);
+	}
 
 	rot->dst = rot->src_rect;
+
 	/*
 	 * by default, rotator output should be placed directly on
 	 * output buffer address without any offset.
@@ -396,7 +458,8 @@
 
 		if (rot->bwc_mode) {
 			pr_err("Unable to do split rotation with bwc set\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto rot_err;
 		}
 
 		width = rot->src_rect.w;
@@ -406,14 +469,16 @@
 
 		if (width > (MAX_MIXER_WIDTH * 2)) {
 			pr_err("unsupported source width %d\n", width);
-			return -EOVERFLOW;
+			ret = -EOVERFLOW;
+			goto rot_err;
 		}
 
 		if (!rot->next) {
 			tmp = mdss_mdp_rotator_session_alloc();
 			if (!tmp) {
 				pr_err("unable to allocate rot dual session\n");
-				return -ENOMEM;
+				ret = -ENOMEM;
+				goto rot_err;
 			}
 			rot->next = tmp;
 		}
@@ -461,7 +526,16 @@
 
 	rot->params_changed++;
 
-	return 0;
+	req->id = rot->session_id;
+
+ rot_err:
+	mutex_unlock(&rotator_lock);
+	if (ret) {
+		pr_err("Unable to setup rotator session\n");
+		if (rot)
+			mdss_mdp_rotator_release(rot);
+	}
+	return ret;
 }
 
 static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot)
@@ -537,3 +611,70 @@
 
 	return 0;
 }
+
+int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd,
+			    struct msmfb_overlay_data *req)
+{
+	struct mdss_mdp_rotator_session *rot;
+	int ret;
+	u32 flgs;
+
+	mutex_lock(&rotator_lock);
+	rot = mdss_mdp_rotator_session_get(req->id);
+	if (!rot) {
+		pr_err("invalid session id=%x\n", req->id);
+		ret = -ENOENT;
+		goto dst_buf_fail;
+	}
+
+	flgs = rot->flags & MDP_SECURE_OVERLAY_SESSION;
+
+	ret = mdss_mdp_rotator_busy_wait_ex(rot);
+	if (ret) {
+		pr_err("rotator busy wait error\n");
+		goto dst_buf_fail;
+	}
+
+	mdss_mdp_overlay_free_buf(&rot->src_buf);
+	ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
+	if (ret) {
+		pr_err("src_data pmem error\n");
+		goto dst_buf_fail;
+	}
+
+	mdss_mdp_overlay_free_buf(&rot->dst_buf);
+	ret = mdss_mdp_overlay_get_buf(mfd, &rot->dst_buf,
+			&req->dst_data, 1, flgs);
+	if (ret) {
+		pr_err("dst_data pmem error\n");
+		goto dst_buf_fail;
+	}
+
+	ret = mdss_mdp_rotator_queue(rot);
+
+	if (ret)
+		pr_err("rotator queue error session id=%x\n", req->id);
+
+dst_buf_fail:
+	mutex_unlock(&rotator_lock);
+	return ret;
+}
+
+int mdss_mdp_rotator_unset(int ndx)
+{
+	struct mdss_mdp_rotator_session *rot;
+	int ret = 0;
+	mutex_lock(&rotator_lock);
+	rot = mdss_mdp_rotator_session_get(ndx);
+	if (rot) {
+		mdss_mdp_overlay_free_buf(&rot->src_buf);
+		mdss_mdp_overlay_free_buf(&rot->dst_buf);
+
+		rot->pid = 0;
+		if (!list_empty(&rot->list))
+			list_del_init(&rot->list);
+		ret = mdss_mdp_rotator_finish(rot);
+	}
+	mutex_unlock(&rotator_lock);
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 43e77cc..7229995 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -51,13 +51,21 @@
 	struct work_struct commit_work;
 };
 
-static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
+static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format, u8 in_rot90)
 {
 	switch (in_format) {
 	case MDP_RGB_565:
 	case MDP_BGR_565:
-		return MDP_RGB_888;
+		if (in_rot90)
+			return MDP_RGB_888;
+		else
+			return in_format;
 	case MDP_Y_CBCR_H2V2_VENUS:
+	case MDP_Y_CBCR_H2V2:
+		if (in_rot90)
+			return MDP_Y_CRCB_H2V2;
+		else
+			return in_format;
 	case MDP_Y_CB_CR_H2V2:
 	case MDP_Y_CR_CB_GH2V2:
 	case MDP_Y_CR_CB_H2V2:
@@ -67,14 +75,13 @@
 	}
 }
 
-struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
-struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
-
-int mdss_mdp_rotator_setup(struct mdss_mdp_rotator_session *rot);
-int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot);
+int mdss_mdp_rotator_setup(struct msm_fb_data_type *mfd,
+			   struct mdp_overlay *req);
 int mdss_mdp_rotator_release(struct mdss_mdp_rotator_session *rot);
 int mdss_mdp_rotator_release_all(void);
-int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot);
 struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_get(
 	struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync);
+int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd,
+			    struct msmfb_overlay_data *req);
+int mdss_mdp_rotator_unset(int ndx);
 #endif /* MDSS_MDP_ROTATOR_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index a9f3e35..58acb8e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -524,6 +524,7 @@
 		pr_err("unable to get writeback buf ctl=%d\n", ctl->num);
 		/* drop buffer but don't return error */
 		ret = 0;
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_DONE);
 		goto kickoff_fail;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 25f1e7c..75fc095 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -85,6 +85,11 @@
 	bool init_done;
 };
 
+struct mdss_panel_recovery {
+	void (*fxn)(void *ctx);
+	void *data;
+};
+
 /**
  * enum mdss_intf_events - Different events generated by MDP core
  *
@@ -120,8 +125,8 @@
  * @MDSS_EVENT_PANEL_CLK_CTRL:	panel clock control
 				 - 0 clock disable
 				 - 1 clock enable
- * @MDSS_EVENT_DSI_CMDLIST_KOFF: kickoff sending dcs command from command list
  * @MDSS_EVENT_ENABLE_PARTIAL_UPDATE: Event to update ROI of the panel.
+ * @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
  */
 enum mdss_intf_events {
 	MDSS_EVENT_RESET = 1,
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index f7ea557..62704a9 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -40,6 +40,14 @@
 	}
 
 	dev = &pdev->dev;
+	ctrl_pdata->mdp_core_clk = clk_get(dev, "mdp_core_clk");
+	if (IS_ERR(ctrl_pdata->mdp_core_clk)) {
+		rc = PTR_ERR(ctrl_pdata->mdp_core_clk);
+		pr_err("%s: Unable to get mdp core clk. rc=%d\n",
+			__func__, rc);
+		goto mdss_dsi_clk_err;
+	}
+
 	ctrl_pdata->ahb_clk = clk_get(dev, "iface_clk");
 	if (IS_ERR(ctrl_pdata->ahb_clk)) {
 		rc = PTR_ERR(ctrl_pdata->ahb_clk);
@@ -101,6 +109,8 @@
 		clk_put(ctrl_pdata->axi_clk);
 	if (ctrl_pdata->ahb_clk)
 		clk_put(ctrl_pdata->ahb_clk);
+	if (ctrl_pdata->mdp_core_clk)
+		clk_put(ctrl_pdata->mdp_core_clk);
 }
 
 #define PREF_DIV_RATIO 27
@@ -241,9 +251,17 @@
 {
 	int rc = 0;
 
+	rc = clk_prepare_enable(ctrl_pdata->mdp_core_clk);
+	if (rc) {
+		pr_err("%s: failed to enable mdp_core_clock. rc=%d\n",
+							 __func__, rc);
+		goto error;
+	}
+
 	rc = clk_prepare_enable(ctrl_pdata->ahb_clk);
 	if (rc) {
 		pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+		clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
 		goto error;
 	}
 
@@ -251,6 +269,7 @@
 	if (rc) {
 		pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
 		clk_disable_unprepare(ctrl_pdata->ahb_clk);
+		clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
 		goto error;
 	}
 
@@ -262,6 +281,7 @@
 {
 	clk_disable_unprepare(ctrl_pdata->axi_clk);
 	clk_disable_unprepare(ctrl_pdata->ahb_clk);
+	clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
 }
 
 static int mdss_dsi_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index c2ad2b4..85be7c3 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -64,8 +64,10 @@
 	WCD9XXX_IRQ_PA2_STARTUP,
 	WCD9XXX_IRQ_PA3_STARTUP,
 	WCD9XXX_IRQ_PA4_STARTUP,
+	WCD9306_IRQ_HPH_PA_OCPR_FAULT = WCD9XXX_IRQ_PA4_STARTUP,
 	WCD9XXX_IRQ_PA5_STARTUP,
 	WCD9XXX_IRQ_MICBIAS1_PRECHARGE,
+	WCD9306_IRQ_HPH_PA_OCPL_FAULT = WCD9XXX_IRQ_MICBIAS1_PRECHARGE,
 	WCD9XXX_IRQ_MICBIAS2_PRECHARGE,
 	WCD9XXX_IRQ_MICBIAS3_PRECHARGE,
 	/* INTR_REG 2 */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 186fff1..08ca341 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -252,6 +252,7 @@
 	struct mutex ios_mutex;
 	enum sdhci_power_policy power_policy;
 
+	u32 auto_cmd_err_sts;
 	unsigned long private[0] ____cacheline_aligned;
 };
 #endif /* LINUX_MMC_SDHCI_H */
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index cfaaa69..0844dc3 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -205,7 +205,16 @@
 #else
 static inline struct page *__page_cache_alloc(gfp_t gfp)
 {
-	return alloc_pages(gfp, 0);
+	struct page *page;
+
+	page = alloc_pages(gfp, 0);
+
+	if (page && is_cma_pageblock(page)) {
+		__free_page(page);
+		page = alloc_pages(gfp & ~__GFP_MOVABLE, 0);
+	}
+
+	return page;
 }
 #endif
 
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 93af04d..22b004e 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -101,6 +101,7 @@
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
 	POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
@@ -320,6 +321,7 @@
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
 	case POWER_SUPPLY_PROP_POWER_NOW:
 		return 1;
 	default:
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index be92ca7..07f9b90 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -339,6 +339,7 @@
  * @host_bus_suspend: indicates host bus suspend or not.
  * @chg_check_timer: The timer used to implement the workaround to detect
  *               very slow plug in of wall charger.
+ * @ui_enabled: USB Intterupt is enabled or disabled.
  */
 struct msm_otg {
 	struct usb_phy phy;
@@ -449,6 +450,7 @@
 	bool ext_chg_opened;
 	bool ext_chg_active;
 	struct completion ext_chg_wait;
+	int ui_enabled;
 };
 
 struct ci13xxx_platform_data {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index af206c7..560accb 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1891,6 +1891,19 @@
 	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE \
+	(V4L2_CID_MPEG_MSM_VIDC_BASE + 34)
+enum v4l2_mpeg_vidc_video_deinterlace {
+	V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 35)
+enum v4l2_mpeg_vidc_video_decoder_multi_stream {
+	V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 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 717bd73..39357e0 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -79,6 +79,13 @@
 int wcnss_xo_auto_detect_enabled(void);
 u32 wcnss_get_wlan_rx_buff_count(void);
 int wcnss_wlan_iris_xo_mode(void);
+#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
+void wcnss_log_debug_regs_on_bite(void);
+#else
+static inline void wcnss_log_debug_regs_on_bite(void)
+{
+}
+#endif
 
 #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_cam_sensor.h b/include/media/msm_cam_sensor.h
index 326e8bf..cccf851 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -48,6 +48,12 @@
 
 #define MAX_AF_ITERATIONS 3
 
+enum flash_type {
+	LED_FLASH = 1,
+	STROBE_FLASH,
+	GPIO_FLASH
+};
+
 enum msm_camera_i2c_reg_addr_type {
 	MSM_CAMERA_I2C_BYTE_ADDR = 1,
 	MSM_CAMERA_I2C_WORD_ADDR,
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index 65831db..ddf9c8e 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -6,7 +6,76 @@
 #endif
 
 enum color_fmts {
+	/* Venus NV12:
+	 * YUV 4:2:0 image with a plane of 8 bit Y samples followed
+	 * by an interleaved U/V plane containing 8 bit 2x2 subsampled
+	 * colour difference samples.
+	 *
+	 * <-------- Y/UV_Stride -------->
+	 * <------- Width ------->
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  ^           ^
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  Height      |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |          Y_Scanlines
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  V           |
+	 * X X X X X X X X X X X X X X X X              |
+	 * X X X X X X X X X X X X X X X X              |
+	 * X X X X X X X X X X X X X X X X              |
+	 * X X X X X X X X X X X X X X X X              V
+	 * U V U V U V U V U V U V X X X X  ^
+	 * U V U V U V U V U V U V X X X X  |
+	 * U V U V U V U V U V U V X X X X  |
+	 * U V U V U V U V U V U V X X X X  UV_Scanlines
+	 * X X X X X X X X X X X X X X X X  |
+	 * X X X X X X X X X X X X X X X X  V
+	 * X X X X X X X X X X X X X X X X  --> Buffer size alignment
+	 *
+	 * Y_Stride : Width aligned to 128
+	 * UV_Stride : Width aligned to 128
+	 * Y_Scanlines: Height aligned to 32
+	 * UV_Scanlines: Height/2 aligned to 16
+	 * Total size = align((Y_Stride * Y_Scanlines
+	 *          + UV_Stride * UV_Scanlines + 4096), 4096)
+	 */
 	COLOR_FMT_NV12,
+
+	/* Venus NV21:
+	 * YUV 4:2:0 image with a plane of 8 bit Y samples followed
+	 * by an interleaved V/U plane containing 8 bit 2x2 subsampled
+	 * colour difference samples.
+	 *
+	 * <-------- Y/UV_Stride -------->
+	 * <------- Width ------->
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  ^           ^
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  Height      |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |          Y_Scanlines
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y X X X X  V           |
+	 * X X X X X X X X X X X X X X X X              |
+	 * X X X X X X X X X X X X X X X X              |
+	 * X X X X X X X X X X X X X X X X              |
+	 * X X X X X X X X X X X X X X X X              V
+	 * V U V U V U V U V U V U X X X X  ^
+	 * V U V U V U V U V U V U X X X X  |
+	 * V U V U V U V U V U V U X X X X  |
+	 * V U V U V U V U V U V U X X X X  UV_Scanlines
+	 * X X X X X X X X X X X X X X X X  |
+	 * X X X X X X X X X X X X X X X X  V
+	 * X X X X X X X X X X X X X X X X  --> Padding & Buffer size alignment
+	 *
+	 * Y_Stride : Width aligned to 128
+	 * UV_Stride : Width aligned to 128
+	 * Y_Scanlines: Height aligned to 32
+	 * UV_Scanlines: Height/2 aligned to 16
+	 * Total size = align((Y_Stride * Y_Scanlines
+	 *          + UV_Stride * UV_Scanlines + 4096), 4096)
+	 */
 	COLOR_FMT_NV21,
 };
 
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index cc37cd8..8e3aced 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 #include <linux/scatterlist.h>
+#include <linux/device.h>
 
 struct scsi_cmnd;
 
diff --git a/include/video/Kbuild b/include/video/Kbuild
index 53e13cb..fce6fd1 100644
--- a/include/video/Kbuild
+++ b/include/video/Kbuild
@@ -2,3 +2,4 @@
 header-y += sisfb.h
 header-y += uvesafb.h
 header-y += msm_hdmi_modes.h
+header-y += msm_hdmi_hdcp_mgr.h
diff --git a/include/video/msm_hdmi_hdcp_mgr.h b/include/video/msm_hdmi_hdcp_mgr.h
new file mode 100644
index 0000000..7b8e7f5
--- /dev/null
+++ b/include/video/msm_hdmi_hdcp_mgr.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_HDMI_HDCP_MGR_H
+#define MSM_HDMI_HDCP_MGR_H
+
+enum DS_TYPE {  /* type of downstream device */
+	DS_UNKNOWN,
+	DS_RECEIVER,
+	DS_REPEATER,
+};
+
+enum {
+	MSG_ID_IDX,
+	RET_CODE_IDX,
+	HEADER_LEN,
+};
+
+enum RET_CODE {
+	HDCP_NOT_AUTHED,
+	HDCP_AUTHED,
+	HDCP_DISABLE,
+};
+
+enum MSG_ID { /* List of functions expected to be called after it */
+	DOWN_CHECK_TOPOLOGY,
+	UP_REQUEST_TOPOLOGY,
+	UP_SEND_TOPOLOGY,
+	DOWN_REQUEST_TOPOLOGY,
+	MSG_NUM,
+};
+
+enum SOURCE_ID {
+	HDCP_V1_TX,
+	HDCP_V1_RX,
+	HDCP_V2_RX,
+	HDCP_V2_TX,
+	SRC_NUM,
+};
+
+/*
+ * how to parse sysfs params buffer
+ * from hdcp_tx driver.
+ */
+
+struct HDCP_V2V1_MSG_TOPOLOGY {
+	/* indicates downstream's type */
+	uint32_t ds_type;
+	uint8_t bksv[5];
+	uint8_t dev_count;
+	uint8_t depth;
+	uint8_t ksv_list[5 * 127];
+	uint32_t max_cascade_exceeded;
+	uint32_t max_dev_exceeded;
+};
+
+#endif /* MSM_HDMI_HDCP_MGR_H */
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index d66b213..8432330 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -681,23 +681,69 @@
  */
 static void timekeeping_resume(void)
 {
+	struct timekeeper *tk = &timekeeper;
+	struct clocksource *clock = tk->clock;
 	unsigned long flags;
-	struct timespec ts;
+	struct timespec ts_new, ts_delta;
+	cycle_t cycle_now, cycle_delta;
+	bool suspendtime_found = false;
 
-	read_persistent_clock(&ts);
+	read_persistent_clock(&ts_new);
 
 	clocksource_resume();
 
 	write_seqlock_irqsave(&timekeeper.lock, flags);
 
-	if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
-		ts = timespec_sub(ts, timekeeping_suspend_time);
-		__timekeeping_inject_sleeptime(&ts);
+	/*
+	 * After system resumes, we need to calculate the suspended time and
+	 * compensate it for the OS time. There are 3 sources that could be
+	 * used: Nonstop clocksource during suspend, persistent clock and rtc
+	 * device.
+	 *
+	 * One specific platform may have 1 or 2 or all of them, and the
+	 * preference will be:
+	 *	suspend-nonstop clocksource -> persistent clock -> rtc
+	 * The less preferred source will only be tried if there is no better
+	 * usable source. The rtc part is handled separately in rtc core code.
+	 */
+	cycle_now = clock->read(clock);
+	if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
+		cycle_now > clock->cycle_last) {
+		u64 num, max = ULLONG_MAX;
+		u32 mult = clock->mult;
+		u32 shift = clock->shift;
+		s64 nsec = 0;
+
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/*
+		 * "cycle_delta * mutl" may cause 64 bits overflow, if the
+		 * suspended time is too long. In that case we need do the
+		 * 64 bits math carefully
+		 */
+		do_div(max, mult);
+		if (cycle_delta > max) {
+			num = div64_u64(cycle_delta, max);
+			nsec = (((u64) max * mult) >> shift) * num;
+			cycle_delta -= num * max;
+		}
+		nsec += ((u64) cycle_delta * mult) >> shift;
+
+		ts_delta = ns_to_timespec(nsec);
+		suspendtime_found = true;
+	} else if (timespec_compare(&ts_new, &timekeeping_suspend_time) > 0) {
+		ts_delta = timespec_sub(ts_new, timekeeping_suspend_time);
+		suspendtime_found = true;
 	}
-	/* re-base the last cycle value */
-	timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
-	timekeeper.ntp_error = 0;
+
+	if (suspendtime_found)
+		__timekeeping_inject_sleeptime(&ts_delta);
+
+	/* Re-base the last cycle value */
+	clock->cycle_last = cycle_now;
+	tk->ntp_error = 0;
 	timekeeping_suspended = 0;
+	timekeeping_update(false);
 	write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
 	touch_softlockup_watchdog();
diff --git a/lib/klist.c b/lib/klist.c
index 0874e41..358a368 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -193,10 +193,10 @@
 		if (waiter->node != n)
 			continue;
 
+		list_del(&waiter->list);
 		waiter->woken = 1;
 		mb();
 		wake_up_process(waiter->process);
-		list_del(&waiter->list);
 	}
 	spin_unlock(&klist_remove_lock);
 	knode_set_klist(n, NULL);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
old mode 100644
new mode 100755
index e9a0ac8..b96094c
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2187,10 +2187,15 @@
 		 * However if a driver requested this specific regulatory
 		 * domain we keep it for its private use
 		 */
-		if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER)
+		if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
+			const struct ieee80211_regdomain *tmp;
+
+			tmp = request_wiphy->regd;
 			request_wiphy->regd = rd;
-		else
+			kfree(tmp);
+		} else {
 			kfree(rd);
+		}
 
 		rd = NULL;
 
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 06d617b..db94741 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1672,6 +1672,11 @@
 	switch (runtime->access) {
 	case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
 	case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
+		if ((UINT_MAX/width) < info->channel) {
+			snd_printd("%s: integer overflow while multiply\n",
+				   __func__);
+			return -EINVAL;
+		}
 		info->first = info->channel * width;
 		info->step = runtime->channels * width;
 		break;
@@ -1679,6 +1684,12 @@
 	case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
 	{
 		size_t size = runtime->dma_bytes / runtime->channels;
+
+		if ((size > 0) && ((UINT_MAX/(size * 8)) < info->channel)) {
+			snd_printd("%s: integer overflow while multiply\n",
+				   __func__);
+			return -EINVAL;
+		}
 		info->first = info->channel * size * 8;
 		info->step = width;
 		break;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8bba8d7..7504576 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -448,7 +448,8 @@
 	runtime->silence_threshold = 0;
 	runtime->silence_size = 0;
 	runtime->boundary = runtime->buffer_size;
-	while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+	while (runtime->boundary * 2 * runtime->channels <=
+					LONG_MAX - runtime->buffer_size)
 		runtime->boundary *= 2;
 
 	snd_pcm_timer_resolution_change(substream);
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 56cd5e6..a3ed23d 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -53,7 +53,7 @@
 snd-soc-cs8427-objs := cs8427.o
 snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
 snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o wcd9xxx-common.o
-snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
+snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o wcd9xxx-common.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 4c20bb9..6785fe1 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -39,6 +39,7 @@
 #include "wcd9xxx-resmgr.h"
 #include "msm8x10_wcd_registers.h"
 #include "../msm/qdsp6v2/q6core.h"
+#include "wcd9xxx-common.h"
 
 #define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
@@ -63,6 +64,15 @@
 #define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
 #define HELICON_MCLK_CLK_9P6MHZ				9600000
 
+/*
+ * Multiplication factor to compute impedance on codec
+ * This is computed from (Vx / (m*Ical)) = (10mV/(180*30uA))
+ */
+#define MSM8X10_WCD_ZDET_MUL_FACTOR 1852
+
+/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
+#define MSM8X10_WCD_WG_TIME_FACTOR_US  240
+
 enum {
 	MSM8X10_WCD_I2C_TOP_LEVEL = 0,
 	MSM8X10_WCD_I2C_ANALOG,
@@ -168,6 +178,12 @@
 
 	struct delayed_work hs_detect_work;
 	struct wcd9xxx_mbhc_config *mbhc_cfg;
+
+	/*
+	 * list used to save/restore registers at start and
+	 * end of impedance measurement
+	 */
+	struct list_head reg_save_restore;
 };
 
 static unsigned short rx_digital_gain_reg[] = {
@@ -192,7 +208,7 @@
 	struct msm8x10_wcd_regulator *vreg,
 	const char *vreg_name, bool ondemand);
 static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
-	struct msm8x10_wcd_micbias_setting *micbias);
+	struct wcd9xxx_micbias_setting *micbias);
 static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
 	struct device *dev);
 
@@ -435,8 +451,8 @@
 				__func__, reg);
 	else
 		dev_dbg(msm8x10_wcd->dev,
-				"%s: Codec reg 0x%x written with value 0x%x\n",
-				__func__, reg, val);
+			"%s: Write %x to R%d(0x%x)\n",
+			__func__, val, reg, reg);
 
 	return ret;
 }
@@ -609,13 +625,24 @@
 }
 
 static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
-	struct msm8x10_wcd_micbias_setting *micbias)
+	struct wcd9xxx_micbias_setting *micbias)
 {
 	int ret = 0;
 	char prop_name[CODEC_DT_MAX_PROP_SIZE];
 	u32 prop_val;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		 "qcom,cdc-micbias-ldoh-v");
+	ret = of_property_read_u32(dev->of_node, prop_name,
+				   &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->ldoh_v = (u8) prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
 		 "qcom,cdc-micbias-cfilt-mv");
 	ret = of_property_read_u32(dev->of_node, prop_name,
 				   &micbias->cfilt1_mv);
@@ -2515,7 +2542,7 @@
 
 	/* Disable internal biasing path which can cause leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
+
 	/* Enable pulldown to reduce leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
@@ -2612,12 +2639,6 @@
 			0xE0, 0xE0);
 }
 
-static int msm8x10_wcd_get_jack_detect_irq(
-		struct snd_soc_codec *codec)
-{
-	return MSM8X10_WCD_IRQ_MBHC_HS_DET;
-}
-
 static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
 	struct wcd9xxx_mbhc *mbhc, bool fast)
 {
@@ -2642,14 +2663,6 @@
 			mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
 }
 
-static void msm8x10_wcd_free_irq(struct wcd9xxx_mbhc *mbhc)
-{
-	struct msm8x10_wcd *msm8x10_wcd = mbhc->codec->control_data;
-	struct wcd9xxx_core_resource *core_res =
-			&msm8x10_wcd->wcd9xxx_res;
-	wcd9xxx_free_irq(core_res, MSM8X10_WCD_IRQ_MBHC_HS_DET, mbhc);
-}
-
 enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
 {
 	return WCD9XXX_CDC_TYPE_HELICON;
@@ -2703,20 +2716,242 @@
 			    0x40, on ? 0x40 : 0x00);
 }
 
+static void msm8x10_wcd_prepare_hph_pa(struct snd_soc_codec *codec,
+				       struct list_head *lh)
+{
+	int i;
+	u32 delay;
+
+	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
+		{MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xFF, 0x01},
+		{MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x01},
+		{MSM8X10_WCD_A_RX_HPH_L_GAIN, 0xFF, 0x2C},
+		{MSM8X10_WCD_A_RX_HPH_R_GAIN, 0xFF, 0x2C},
+		{MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0xFF, 0x01},
+		{MSM8X10_WCD_A_RX_COM_BIAS, 0xFF, 0x80},
+		{MSM8X10_WCD_A_CP_EN, 0xFF, 0xE7},
+		{MSM8X10_WCD_A_CP_STATIC, 0xFF, 0x13},
+		{MSM8X10_WCD_A_CP_STATIC, 0xFF, 0x1B},
+		{MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x01},
+		{MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0xFF, 0x03},
+		{MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0xFF, 0x22},
+		{MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0xFF, 0x23},
+		{MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDA},
+		{MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0xFF, 0x01},
+		{MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0xFF, 0x03},
+		{MSM8X10_WCD_A_RX_HPH_CHOP_CTL, 0xFF, 0xA4},
+		{MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xFF, 0x67},
+		{MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x00},
+		{MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x00},
+		{MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
+		{MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
+		{MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME, 0xFF, 0xDB},
+		{MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0xFF, 0x40},
+		{MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0xFF, 0xC0},
+		{MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0xFF, 0x40},
+		{MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0xFF, 0xC0},
+		{MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0x03, 0x01},
+		{MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0x03, 0x01},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
+		delay = 0;
+		wcd9xxx_soc_update_bits_push(codec, lh,
+					     reg_set_paon[i].reg,
+					     reg_set_paon[i].mask,
+					     reg_set_paon[i].val, delay);
+	}
+	dev_dbg(codec->dev, "%s: PAs are prepared\n", __func__);
+	return;
+}
+
+static int msm8x10_wcd_enable_static_pa(struct snd_soc_codec *codec,
+					bool enable)
+{
+	int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
+				MSM8X10_WCD_WG_TIME_FACTOR_US;
+
+	wg_time += (int) (wg_time * 35) / 100;
+
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_HPH_CNP_EN, 0x30,
+			    enable ? 0x30 : 0x0);
+	/* Wait for wave gen time to avoid pop noise */
+	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xFF, 0x00);
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x00);
+
+	dev_dbg(codec->dev, "%s: PAs are %s as static mode (wg_time %d)\n",
+		__func__, enable ? "enabled" : "disabled", wg_time);
+	return 0;
+}
+
+static int msm8x10_wcd_setup_zdet(struct wcd9xxx_mbhc *mbhc,
+				  enum mbhc_impedance_detect_stages stage)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct msm8x10_wcd_priv *wcd_priv = snd_soc_codec_get_drvdata(codec);
+	const int mux_wait_us = 25;
+
+#define __wr(reg, mask, value)					\
+	do {							\
+		ret = wcd9xxx_soc_update_bits_push(codec,	\
+				&wcd_priv->reg_save_restore,	\
+				reg, mask, value, 0);		\
+		if (ret < 0)					\
+			return ret;				\
+	 } while (0)
+
+	switch (stage) {
+	case PRE_MEAS:
+		dev_dbg(codec->dev, "%s: PRE_MEAS\n", __func__);
+		INIT_LIST_HEAD(&wcd_priv->reg_save_restore);
+		/* Configure PA */
+		msm8x10_wcd_prepare_hph_pa(mbhc->codec,
+					   &wcd_priv->reg_save_restore);
+
+		/* Setup MBHC */
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0x7F, 0x40);
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
+		__wr(0x171, 0xFF, 0x90);
+		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0xF0);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xFF, 0x45);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x80);
+
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
+
+		/* Enable Impedance Detection */
+		__wr(WCD9XXX_A_MBHC_HPH, 0xFF, 0xC8);
+
+		/*
+		 * CnP setup for 0mV
+		 * Route static data as input to noise shaper
+		 */
+		__wr(MSM8X10_WCD_A_CDC_RX1_B3_CTL, 0xFF, 0x02);
+		__wr(MSM8X10_WCD_A_CDC_RX2_B3_CTL, 0xFF, 0x02);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
+				    0x02, 0x00);
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
+				    0x02, 0x00);
+
+		/* Reset the HPHL static data pointer */
+		__wr(MSM8X10_WCD_A_CDC_RX1_B2_CTL, 0xFF, 0x00);
+		/* Four consecutive writes to set 0V as static data input */
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
+
+		/* Reset the HPHR static data pointer */
+		__wr(MSM8X10_WCD_A_CDC_RX2_B2_CTL, 0xFF, 0x00);
+		/* Four consecutive writes to set 0V as static data input */
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
+
+		/* Enable the HPHL and HPHR PA */
+		msm8x10_wcd_enable_static_pa(mbhc->codec, true);
+		break;
+
+	case POST_MEAS:
+		dev_dbg(codec->dev, "%s: POST_MEAS\n", __func__);
+		/* Turn off ICAL */
+		snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);
+
+		msm8x10_wcd_enable_static_pa(mbhc->codec, false);
+
+		/*
+		 * Setup CnP wavegen to ramp to the desired
+		 * output using a 40ms ramp
+		 */
+
+		/* CnP wavegen current to 0.5uA */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0x1A);
+		/* Set the current division ratio to 2000 */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xDF);
+		/* Set the wavegen timer to max (60msec) */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xA0);
+		/* Set the CnP reference current to sc_bias */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x6D);
+
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B2_CTL, 0x00);
+		/* Four consecutive writes to set -10mV as static data input */
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x1F);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0xE3);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x08);
+
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B2_CTL, 0x00);
+		/* Four consecutive writes to set -10mV as static data input */
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x1F);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0xE3);
+		snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x08);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
+				    0x02, 0x02);
+		/* Enable the HPHL and HPHR PA and wait for 60mS */
+		msm8x10_wcd_enable_static_pa(mbhc->codec, true);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x7F, 0x40);
+		usleep_range(mux_wait_us,
+				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		break;
+	case PA_DISABLE:
+		dev_dbg(codec->dev, "%s: PA_DISABLE\n", __func__);
+		msm8x10_wcd_enable_static_pa(mbhc->codec, false);
+		wcd9xxx_restore_registers(codec, &wcd_priv->reg_save_restore);
+		break;
+	}
+#undef __wr
+
+	return ret;
+}
+
+static void msm8x10_wcd_compute_impedance(s16 *l, s16 *r, uint32_t *zl,
+					  uint32_t *zr)
+{
+	int zln, zld;
+	int zrn, zrd;
+	int rl = 0, rr = 0;
+
+	zln = (l[1] - l[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
+	zld = (l[2] - l[0]);
+	if (zld)
+		rl = zln / zld;
+
+	zrn = (r[1] - r[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
+	zrd = (r[2] - r[0]);
+	if (zrd)
+		rr = zrn / zrd;
+
+	*zl = rl;
+	*zr = rr;
+}
+
+
+
 static const struct wcd9xxx_mbhc_cb mbhc_cb = {
 	.enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
 	.cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
 	.codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
-	.jack_detect_irq = msm8x10_wcd_get_jack_detect_irq,
 	.switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
 	.select_cfilt = msm8x10_wcd_select_cfilt,
-	.free_irq = msm8x10_wcd_free_irq,
 	.get_cdc_type = msm8x10_wcd_get_cdc_type,
 	.enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
 	.enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
 	.enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
 	.setup_int_rbias = msm8x10_wcd_micb_internal,
 	.pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
+	.setup_zdet = msm8x10_wcd_setup_zdet,
+	.compute_impedance = msm8x10_wcd_compute_impedance,
 };
 
 static void delayed_hs_detect_fn(struct work_struct *work)
@@ -2819,6 +3054,52 @@
 	.priority = -INT_MAX,
 };
 
+static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
+	.poll_plug_rem = MSM8X10_WCD_IRQ_MBHC_REMOVAL,
+	.shortavg_complete = MSM8X10_WCD_IRQ_MBHC_SHORT_TERM,
+	.potential_button_press = MSM8X10_WCD_IRQ_MBHC_PRESS,
+	.button_release = MSM8X10_WCD_IRQ_MBHC_RELEASE,
+	.dce_est_complete = MSM8X10_WCD_IRQ_MBHC_POTENTIAL,
+	.insertion = MSM8X10_WCD_IRQ_MBHC_INSERTION,
+	.hph_left_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT,
+	.hph_right_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT,
+	.hs_jack_switch = MSM8X10_WCD_IRQ_MBHC_HS_DET,
+};
+
+static int msm8x10_wcd_handle_pdata(struct snd_soc_codec *codec,
+	struct msm8x10_wcd_pdata *pdata)
+{
+	int k1, rc = 0;
+	struct msm8x10_wcd_priv *msm8x10_wcd_priv;
+
+	msm8x10_wcd_priv = snd_soc_codec_get_drvdata(codec);
+
+	/* Make sure settings are correct */
+	if (pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V ||
+	    pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT1_SEL) {
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* figure out k value */
+	k1 = wcd9xxx_resmgr_get_k_val(&msm8x10_wcd_priv->resmgr,
+				 pdata->micbias.cfilt1_mv);
+	if (IS_ERR_VALUE(k1)) {
+		rc = -EINVAL;
+		goto done;
+	}
+
+	/* Set voltage level */
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_VAL,
+			    0xFC, (k1 << 2));
+
+	/* update micbias capless mode */
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
+			    pdata->micbias.bias1_cap_mode << 4);
+
+done:
+	return rc;
+}
 
 static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
 {
@@ -2856,12 +3137,18 @@
 	INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
 			delayed_hs_detect_fn);
 
+	pdata = dev_get_platdata(msm8x10_wcd->dev);
+	if (!pdata) {
+		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
+			__func__);
+	}
+
 	/* codec resmgr module init */
 	msm8x10_wcd = codec->control_data;
 	core_res = &msm8x10_wcd->wcd9xxx_res;
 	ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
-				codec, core_res, NULL, NULL,
-				WCD9XXX_CDC_TYPE_HELICON);
+				codec, core_res, NULL, &pdata->micbias,
+				NULL, WCD9XXX_CDC_TYPE_HELICON);
 	if (ret) {
 		dev_err(codec->dev,
 				"%s: wcd9xxx init failed %d\n",
@@ -2873,16 +3160,6 @@
 	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
 
-	pdata = dev_get_platdata(msm8x10_wcd->dev);
-	if (!pdata) {
-		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
-			__func__);
-	}
-
-	/* update micbias capless mode */
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
-			    pdata->micbias.bias1_cap_mode << 4);
-
 	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
@@ -2896,13 +3173,19 @@
 
 	ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
 				&msm8x10_wcd_priv->resmgr,
-				codec, NULL, &mbhc_cb,
-				HELICON_MCLK_CLK_9P6MHZ, false);
+				codec, NULL, &mbhc_cb, &cdc_intr_ids,
+				HELICON_MCLK_CLK_9P6MHZ, true);
 	if (ret) {
-		pr_err("%s: Failed to initialize mbhc\n", __func__);
+		dev_err(msm8x10_wcd->dev, "%s: Failed to initialize mbhc\n",
+			__func__);
 		goto exit_probe;
 	}
 
+	/* Handle the Pdata */
+	ret = msm8x10_wcd_handle_pdata(codec, pdata);
+	if (IS_ERR_VALUE(ret))
+		dev_err(msm8x10_wcd->dev, "%s: Bad Pdata\n", __func__);
+
 	registered_codec = codec;
 	adsp_state_notifier =
 	    subsys_notif_register_notifier("adsp",
@@ -3207,6 +3490,11 @@
 		dev_dbg(&client->dev, "%s:Platform data from device tree\n",
 			__func__);
 		pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
+		if (!pdata) {
+			dev_err(&client->dev, "%s: Failed to parse pdata from device tree\n",
+				__func__);
+			goto rtn;
+		}
 		client->dev.platform_data = pdata;
 	} else {
 		dev_dbg(&client->dev, "%s:Platform data from board file\n",
@@ -3316,12 +3604,61 @@
 	{ },
 };
 
+#ifdef CONFIG_PM
+static int msm8x10_wcd_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct msm8x10_wcd_priv *priv = i2c_get_clientdata(client);
+	struct msm8x10_wcd *msm8x10;
+	int ret =  0;
+
+	if (client->addr == HELICON_CORE_0_I2C_ADDR) {
+		if (!priv || !priv->codec || !priv->codec->control_data) {
+			ret = -EINVAL;
+			dev_err(dev, "%s: Invalid client data\n", __func__);
+			goto rtn;
+		}
+		msm8x10 = priv->codec->control_data;
+		return wcd9xxx_core_res_resume(&msm8x10->wcd9xxx_res);
+	}
+rtn:
+	return 0;
+}
+
+static int msm8x10_wcd_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct msm8x10_wcd_priv *priv = i2c_get_clientdata(client);
+	struct msm8x10_wcd *msm8x10;
+	int ret = 0;
+
+	if (client->addr == HELICON_CORE_0_I2C_ADDR) {
+		if (!priv || !priv->codec || !priv->codec->control_data) {
+			ret = -EINVAL;
+			dev_err(dev, "%s: Invalid client data\n", __func__);
+			goto rtn;
+		}
+		msm8x10 = priv->codec->control_data;
+		return wcd9xxx_core_res_suspend(&msm8x10->wcd9xxx_res,
+						PMSG_SUSPEND);
+	}
+
+rtn:
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(msm8x1_wcd_pm_ops, msm8x10_wcd_i2c_suspend,
+			 msm8x10_wcd_i2c_resume);
+#endif
 
 static struct i2c_driver msm8x10_wcd_i2c_driver = {
 	.driver                 = {
 		.owner          = THIS_MODULE,
 		.name           = "msm8x10-wcd-i2c-core",
-		.of_match_table = msm8x10_wcd_of_match
+		.of_match_table = msm8x10_wcd_of_match,
+#ifdef CONFIG_PM
+		.pm = &msm8x1_wcd_pm_ops,
+#endif
 	},
 	.id_table               = msm8x10_wcd_id_table,
 	.probe                  = msm8x10_wcd_i2c_probe,
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 5f67cba..eeeb557 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -16,6 +16,7 @@
 #include <sound/jack.h>
 #include "wcd9xxx-mbhc.h"
 #include "wcd9xxx-resmgr.h"
+#include <linux/mfd/wcd9xxx/pdata.h>
 
 #define MSM8X10_WCD_NUM_REGISTERS	0x600
 #define MSM8X10_WCD_MAX_REGISTER	(MSM8X10_WCD_NUM_REGISTERS-1)
@@ -113,28 +114,6 @@
 	MSM8X10_WCD_NUM_IRQS,
 };
 
-/*
- * Each micbias can be assigned to one of three cfilters
- * Vbatt_min >= .15V + ldoh_v
- * ldoh_v >= .15v + cfiltx_mv
- * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
- * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
- * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
- * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
- */
-struct msm8x10_wcd_micbias_setting {
-	u8 ldoh_v;
-	u32 cfilt1_mv; /* in mv */
-	/*
-	 * Different WCD9xxx series codecs may not
-	 * have 4 mic biases. If a codec has fewer
-	 * mic biases, some of these properties will
-	 * not be used.
-	 */
-	u8 bias1_cfilt_sel;
-	u8 bias1_cap_mode;
-};
-
 struct msm8x10_wcd_ocp_setting {
 	unsigned int	use_pdata:1; /* 0 - use sys default as recommended */
 	unsigned int	num_attempts:4; /* up to 15 attempts */
@@ -158,7 +137,7 @@
 	int num_irqs;
 	int reset_gpio;
 	void *msm8x10_wcd_ahb_base_vaddr;
-	struct msm8x10_wcd_micbias_setting micbias;
+	struct wcd9xxx_micbias_setting micbias;
 	struct msm8x10_wcd_ocp_setting ocp;
 	struct msm8x10_wcd_regulator regulator[MAX_REGULATOR];
 	u32 mclk_rate;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 17ed0d3..da99254 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -97,8 +97,6 @@
 #define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
 #define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
 
-#define TAPAN_IRQ_MBHC_JACK_SWITCH 21
-
 enum tapan_codec_type {
 	WCD9306,
 	WCD9302,
@@ -5086,11 +5084,6 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
 }
 
-static int tapan_get_jack_detect_irq(struct snd_soc_codec *codec)
-{
-	return TAPAN_IRQ_MBHC_JACK_SWITCH;
-}
-
 static struct wcd9xxx_cfilt_mode tapan_codec_switch_cfilt_mode(
 				 struct wcd9xxx_mbhc *mbhc,
 				 bool fast)
@@ -5116,14 +5109,6 @@
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
 }
 
-static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
-{
-	struct wcd9xxx *wcd9xxx = mbhc->codec->control_data;
-	struct wcd9xxx_core_resource *core_res =
-			&wcd9xxx->core_res;
-	wcd9xxx_free_irq(core_res, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
-}
-
 enum wcd9xxx_cdc_type tapan_get_cdc_type(void)
 {
 	return WCD9XXX_CDC_TYPE_TAPAN;
@@ -5382,10 +5367,8 @@
 	.enable_mux_bias_block = tapan_enable_mux_bias_block,
 	.cfilt_fast_mode = tapan_put_cfilt_fast_mode,
 	.codec_specific_cal = tapan_codec_specific_cal_setup,
-	.jack_detect_irq = tapan_get_jack_detect_irq,
 	.switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
 	.select_cfilt = tapan_select_cfilt,
-	.free_irq = tapan_free_irq,
 	.get_cdc_type = tapan_get_cdc_type,
 	.setup_zdet = tapan_setup_zdet,
 	.compute_impedance = tapan_compute_impedance,
@@ -5426,6 +5409,18 @@
 	return 0;
 }
 
+static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
+	.poll_plug_rem = WCD9XXX_IRQ_MBHC_REMOVAL,
+	.shortavg_complete = WCD9XXX_IRQ_MBHC_SHORT_TERM,
+	.potential_button_press = WCD9XXX_IRQ_MBHC_PRESS,
+	.button_release = WCD9XXX_IRQ_MBHC_RELEASE,
+	.dce_est_complete = WCD9XXX_IRQ_MBHC_POTENTIAL,
+	.insertion = WCD9XXX_IRQ_MBHC_INSERTION,
+	.hph_left_ocp = WCD9306_IRQ_HPH_PA_OCPL_FAULT,
+	.hph_right_ocp = WCD9306_IRQ_HPH_PA_OCPR_FAULT,
+	.hs_jack_switch = WCD9306_IRQ_MBHC_JACK_SWITCH,
+};
+
 static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -5473,7 +5468,7 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				&mbhc_cb, rco_clk_rate,
+				&mbhc_cb, &cdc_intr_ids, rco_clk_rate,
 				TAPAN_CDC_ZDET_SUPPORTED);
 	if (ret)
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
@@ -5652,7 +5647,8 @@
 	core_res = &wcd9xxx->core_res;
 	pdata = dev_get_platdata(codec->dev->parent);
 	ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, core_res, pdata,
-				  &tapan_reg_address, WCD9XXX_CDC_TYPE_TAPAN);
+				  &pdata->micbias, &tapan_reg_address,
+				  WCD9XXX_CDC_TYPE_TAPAN);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
 		return ret;
@@ -5679,7 +5675,7 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				&mbhc_cb, rco_clk_rate,
+				&mbhc_cb, &cdc_intr_ids, rco_clk_rate,
 				TAPAN_CDC_ZDET_SUPPORTED);
 
 	if (ret) {
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 2beda38..9cad1e5 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1127,6 +1127,125 @@
 static const struct snd_kcontrol_new class_h_dsm_mux =
 	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
 
+static const char *const taiko_conn_mad_text[] = {
+	"ADC_MB", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "NOTUSED1",
+	"DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6", "NOTUSED2",
+	"NOTUSED3"};
+
+static const struct soc_enum taiko_conn_mad_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(taiko_conn_mad_text),
+			taiko_conn_mad_text);
+
+
+static int taiko_mad_input_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	u8 taiko_mad_input;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	taiko_mad_input = snd_soc_read(codec, TAIKO_A_CDC_CONN_MAD);
+
+	taiko_mad_input = taiko_mad_input & 0x0F;
+
+	ucontrol->value.integer.value[0] = taiko_mad_input;
+
+	pr_debug("%s: taiko_mad_input = %s\n", __func__,
+			taiko_conn_mad_text[taiko_mad_input]);
+
+	return 0;
+}
+
+static int taiko_mad_input_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	u8 taiko_mad_input;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = codec->card;
+	char mad_amic_input_widget[6];
+	u32 adc;
+	const char *mad_input_widget;
+	u32  mic_bias_found = 0;
+	u32 i;
+	int ret = 0;
+
+	taiko_mad_input = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: taiko_mad_input = %s\n", __func__,
+			taiko_conn_mad_text[taiko_mad_input]);
+
+	if (!strcmp(taiko_conn_mad_text[taiko_mad_input], "NOTUSED1") ||
+		!strcmp(taiko_conn_mad_text[taiko_mad_input], "NOTUSED2") ||
+		!strcmp(taiko_conn_mad_text[taiko_mad_input], "NOTUSED3") ||
+		!strcmp(taiko_conn_mad_text[taiko_mad_input], "ADC_MB")) {
+		pr_info("%s: taiko mad input is set to unsupported input = %s\n",
+				__func__, taiko_conn_mad_text[taiko_mad_input]);
+		return -EINVAL;
+	}
+
+	if (strnstr(taiko_conn_mad_text[taiko_mad_input],
+				"ADC", sizeof("ADC"))) {
+		ret = kstrtouint(strpbrk(taiko_conn_mad_text[taiko_mad_input]
+					, "123456"), 10, &adc);
+		if ((ret < 0) || (adc > 6)) {
+			pr_err("%s: Invalid ADC = %s\n", __func__,
+				taiko_conn_mad_text[taiko_mad_input]);
+			ret =  -EINVAL;
+		}
+
+		snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
+
+		mad_input_widget = mad_amic_input_widget;
+		pr_debug("%s: taiko amic input widget = %s\n", __func__,
+			  mad_amic_input_widget);
+	} else {
+		/* DMIC type input widget*/
+		mad_input_widget = taiko_conn_mad_text[taiko_mad_input];
+	}
+
+	pr_debug("%s: taiko input widget = %s\n", __func__, mad_input_widget);
+
+	for (i = 0; i < card->num_dapm_routes; i++) {
+
+		if (!strncmp(card->dapm_routes[i].sink,
+				mad_input_widget, strlen(mad_input_widget))) {
+
+			if (strnstr(card->dapm_routes[i].source,
+				"MIC BIAS1", sizeof("MIC BIAS1"))) {
+				mic_bias_found = 1;
+				break;
+			} else if (strnstr(card->dapm_routes[i].source,
+				"MIC BIAS2", sizeof("MIC BIAS2"))) {
+				mic_bias_found = 2;
+				break;
+			} else if (strnstr(card->dapm_routes[i].source,
+				"MIC BIAS3", sizeof("MIC BIAS3"))) {
+				mic_bias_found = 3;
+				break;
+			} else if (strnstr(card->dapm_routes[i].source,
+				"MIC BIAS4", sizeof("MIC BIAS4"))) {
+				mic_bias_found = 4;
+				break;
+			}
+		}
+	}
+
+	if (mic_bias_found) {
+		pr_debug("%s: source mic bias = %s. sink = %s\n", __func__,
+				card->dapm_routes[i].source,
+				card->dapm_routes[i].sink);
+
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_MAD,
+					0x0F, taiko_mad_input);
+		snd_soc_update_bits(codec, TAIKO_A_MAD_ANA_CTRL,
+					0x07, mic_bias_found);
+		return 0;
+	} else {
+		pr_err("%s: mic bias source not found for input = %s\n",
+				__func__, mad_input_widget);
+		return -EINVAL;
+	}
+}
+
 
 static const struct snd_kcontrol_new taiko_snd_controls[] = {
 
@@ -1275,6 +1394,9 @@
 	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
 		       taiko_get_compander, taiko_set_compander),
 
+	SOC_ENUM_EXT("MAD Input", taiko_conn_mad_enum,
+			taiko_mad_input_get, taiko_mad_input_put),
+
 };
 
 static int taiko_pa_gain_get(struct snd_kcontrol *kcontrol,
@@ -2498,8 +2620,6 @@
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_MAD,
-			    0x0F, mad_cal->microphone_info.input_microphone);
 	snd_soc_write(codec, TAIKO_A_CDC_MAD_MAIN_CTL_2,
 		      mad_cal->microphone_info.cycle_time);
 	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_MAIN_CTL_1, 0xFF << 3,
@@ -6065,6 +6185,9 @@
 
 	/* Program the 0.85 volt VBG_REFERENCE */
 	{TAIKO_A_BIAS_CURR_CTL_2, 0xFF, 0x04},
+
+	/* set MAD input MIC to DMIC1 */
+	{TAIKO_A_CDC_CONN_MAD, 0x0F, 0x08},
 };
 
 static void taiko_codec_init_reg(struct snd_soc_codec *codec)
@@ -6368,6 +6491,18 @@
 	.compute_impedance = taiko_compute_impedance,
 };
 
+static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
+	.poll_plug_rem = WCD9XXX_IRQ_MBHC_REMOVAL,
+	.shortavg_complete = WCD9XXX_IRQ_MBHC_SHORT_TERM,
+	.potential_button_press = WCD9XXX_IRQ_MBHC_PRESS,
+	.button_release = WCD9XXX_IRQ_MBHC_RELEASE,
+	.dce_est_complete = WCD9XXX_IRQ_MBHC_POTENTIAL,
+	.insertion = WCD9XXX_IRQ_MBHC_INSERTION,
+	.hph_left_ocp = WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	.hph_right_ocp = WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+	.hs_jack_switch = WCD9320_IRQ_MBHC_JACK_SWITCH,
+};
+
 static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -6413,7 +6548,8 @@
 
 		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 					taiko_enable_mbhc_micbias,
-					&mbhc_cb, rco_clk_rate, true);
+					&mbhc_cb, &cdc_intr_ids,
+					rco_clk_rate, true);
 		if (ret)
 			pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		else
@@ -6583,7 +6719,8 @@
 	core_res = &wcd9xxx->core_res;
 	pdata = dev_get_platdata(codec->dev->parent);
 	ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, core_res, pdata,
-				  &taiko_reg_address, WCD9XXX_CDC_TYPE_TAIKO);
+				  &pdata->micbias, &taiko_reg_address,
+				  WCD9XXX_CDC_TYPE_TAIKO);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
 		goto err_init;
@@ -6602,7 +6739,8 @@
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 				taiko_enable_mbhc_micbias,
-				&mbhc_cb, rco_clk_rate, true);
+				&mbhc_cb, &cdc_intr_ids,
+				rco_clk_rate, true);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		goto err_init;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 7b29a11..59242b9 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -118,8 +118,6 @@
 /* RX_HPH_CNP_WG_TIME increases by 0.24ms */
 #define WCD9XXX_WG_TIME_FACTOR_US	240
 
-#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT 28
-
 #define WCD9XXX_V_CS_HS_MAX 500
 #define WCD9XXX_V_CS_NO_MIC 5
 #define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
@@ -265,11 +263,6 @@
 static int __wcd9xxx_resmgr_get_k_val(struct wcd9xxx_mbhc *mbhc,
 		unsigned int cfilt_mv)
 {
-	if (mbhc->mbhc_cb &&
-			mbhc->mbhc_cb->get_cdc_type() ==
-					WCD9XXX_CDC_TYPE_HELICON)
-		return 0x18;
-
 	return wcd9xxx_resmgr_get_k_val(mbhc->resmgr, cfilt_mv);
 }
 
@@ -570,7 +563,7 @@
 		 * reset retry counter as PA is turned off signifying
 		 * start of new OCP detection session
 		 */
-		if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
+		if (mbhc->intr_ids->hph_left_ocp)
 			mbhc->hphlocp_cnt = 0;
 		else
 			mbhc->hphrocp_cnt = 0;
@@ -581,54 +574,43 @@
 static void hphrocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
 {
 	__hphocp_off_report(mbhc, SND_JACK_OC_HPHR,
-			    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+			    mbhc->intr_ids->hph_right_ocp);
 }
 
 static void hphlocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
 {
 	__hphocp_off_report(mbhc, SND_JACK_OC_HPHL,
-			    WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+			    mbhc->intr_ids->hph_left_ocp);
 }
 
 static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
 					struct mbhc_micbias_regs *micbias_regs)
 {
 	unsigned int cfilt;
-	struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
-
-	if (mbhc->mbhc_cb &&
-			mbhc->mbhc_cb->get_cdc_type() ==
-					WCD9XXX_CDC_TYPE_HELICON) {
-		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
-		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
-		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
-		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
-		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
-		mbhc->mbhc_data.micb_mv = 1800;
-		return;
-	}
+	struct wcd9xxx_micbias_setting *micbias_pdata =
+		mbhc->resmgr->micbias_pdata;
 
 	switch (mbhc->mbhc_cfg->micbias) {
 	case MBHC_MICBIAS1:
-		cfilt = pdata->micbias.bias1_cfilt_sel;
+		cfilt = micbias_pdata->bias1_cfilt_sel;
 		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
 		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
 		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
 		break;
 	case MBHC_MICBIAS2:
-		cfilt = pdata->micbias.bias2_cfilt_sel;
+		cfilt = micbias_pdata->bias2_cfilt_sel;
 		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_2_MBHC;
 		micbias_regs->int_rbias = WCD9XXX_A_MICB_2_INT_RBIAS;
 		micbias_regs->ctl_reg = WCD9XXX_A_MICB_2_CTL;
 		break;
 	case MBHC_MICBIAS3:
-		cfilt = pdata->micbias.bias3_cfilt_sel;
+		cfilt = micbias_pdata->bias3_cfilt_sel;
 		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_3_MBHC;
 		micbias_regs->int_rbias = WCD9XXX_A_MICB_3_INT_RBIAS;
 		micbias_regs->ctl_reg = WCD9XXX_A_MICB_3_CTL;
 		break;
 	case MBHC_MICBIAS4:
-		cfilt = pdata->micbias.bias4_cfilt_sel;
+		cfilt = micbias_pdata->bias4_cfilt_sel;
 		micbias_regs->mbhc_reg = mbhc->resmgr->reg_addr->micb_4_mbhc;
 		micbias_regs->int_rbias =
 		    mbhc->resmgr->reg_addr->micb_4_int_rbias;
@@ -646,20 +628,17 @@
 	case WCD9XXX_CFILT1_SEL:
 		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
 		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
-		mbhc->mbhc_data.micb_mv =
-		    mbhc->resmgr->pdata->micbias.cfilt1_mv;
+		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt1_mv;
 		break;
 	case WCD9XXX_CFILT2_SEL:
 		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_2_VAL;
 		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_2_CTL;
-		mbhc->mbhc_data.micb_mv =
-		    mbhc->resmgr->pdata->micbias.cfilt2_mv;
+		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt2_mv;
 		break;
 	case WCD9XXX_CFILT3_SEL:
 		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_3_VAL;
 		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_3_CTL;
-		mbhc->mbhc_data.micb_mv =
-		    mbhc->resmgr->pdata->micbias.cfilt3_mv;
+		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt3_mv;
 		break;
 	}
 }
@@ -828,25 +807,28 @@
 		mbhc->current_plug = PLUG_TYPE_NONE;
 		mbhc->polling_active = false;
 	} else {
-		if (mbhc->mbhc_cfg->detect_extn_cable) {
-			/* Report removal of current jack type */
-			if (mbhc->hph_status && mbhc->hph_status != jack_type) {
-				if (mbhc->micbias_enable &&
-				    mbhc->micbias_enable_cb &&
-				    mbhc->hph_status == SND_JACK_HEADSET) {
-					pr_debug("%s: Disabling micbias\n",
-						 __func__);
-					mbhc->micbias_enable_cb(mbhc->codec,
-								false);
-					mbhc->micbias_enable = false;
-				}
-				pr_debug("%s: Reporting removal (%x)\n",
-						__func__, mbhc->hph_status);
-				mbhc->zl = mbhc->zr = 0;
-				wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
-						    0, WCD9XXX_JACK_MASK);
-				mbhc->hph_status = 0;
+		/*
+		 * Report removal of current jack type.
+		 * Headphone to headset shouldn't report headphone
+		 * removal.
+		 */
+		if (mbhc->mbhc_cfg->detect_extn_cable &&
+		    !(mbhc->current_plug == PLUG_TYPE_HEADPHONE &&
+		      jack_type == SND_JACK_HEADSET) &&
+		    (mbhc->hph_status && mbhc->hph_status != jack_type)) {
+			if (mbhc->micbias_enable && mbhc->micbias_enable_cb &&
+			    mbhc->hph_status == SND_JACK_HEADSET) {
+				pr_debug("%s: Disabling micbias\n", __func__);
+				mbhc->micbias_enable_cb(mbhc->codec, false);
+				mbhc->micbias_enable = false;
 			}
+
+			pr_debug("%s: Reporting removal (%x)\n",
+				 __func__, mbhc->hph_status);
+			mbhc->zl = mbhc->zr = 0;
+			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
+					    0, WCD9XXX_JACK_MASK);
+			mbhc->hph_status = 0;
 		}
 		/* Report insertion */
 		mbhc->hph_status |= jack_type;
@@ -972,7 +954,8 @@
 	short bias_value;
 	struct snd_soc_codec *codec = mbhc->codec;
 
-	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res,
+			    mbhc->intr_ids->dce_est_complete);
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, false);
 
@@ -1018,7 +1001,8 @@
 
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, true);
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
+			   mbhc->intr_ids->dce_est_complete);
 
 	return bias_value;
 }
@@ -1957,7 +1941,7 @@
 		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
 				    0x3, mbhc->mbhc_cfg->micbias);
 
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, mbhc->intr_ids->insertion);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 	pr_debug("%s: leave\n", __func__);
 
@@ -2432,7 +2416,7 @@
 
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, mbhc->intr_ids->insertion);
 
 	is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
 			   0x10);
@@ -2499,7 +2483,7 @@
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-	wcd9xxx_disable_irq_sync(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq_sync(core_res, mbhc->intr_ids->insertion);
 	wcd9xxx_mbhc_detect_plug_type(mbhc);
 	wcd9xxx_unlock_sleep(core_res);
 }
@@ -3392,7 +3376,7 @@
 					    0x10, 0x10);
 		} else {
 			wcd9xxx_disable_irq(mbhc->resmgr->core_res,
-					  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+					  mbhc->intr_ids->hph_left_ocp);
 			mbhc->hph_status |= SND_JACK_OC_HPHL;
 			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 					    mbhc->hph_status,
@@ -3422,7 +3406,7 @@
 				    0x10);
 	} else {
 		wcd9xxx_disable_irq(mbhc->resmgr->core_res,
-				    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+				    mbhc->intr_ids->hph_right_ocp);
 		mbhc->hph_status |= SND_JACK_OC_HPHR;
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 				    mbhc->hph_status, WCD9XXX_JACK_MASK);
@@ -3502,7 +3486,8 @@
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
-	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res,
+			    mbhc->intr_ids->dce_est_complete);
 	wcd9xxx_turn_onoff_rel_detection(codec, false);
 
 	/* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
@@ -3642,7 +3627,8 @@
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
 		mbhc->mbhc_cb->enable_mb_source(codec, false);
 
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
+			   mbhc->intr_ids->dce_est_complete);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
 	pr_debug("%s: leave\n", __func__);
@@ -3708,14 +3694,7 @@
 static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
 {
 	int ret = 0;
-	struct snd_soc_codec *codec = mbhc->codec;
 	void *core_res = mbhc->resmgr->core_res;
-	int jack_irq;
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->jack_detect_irq)
-		jack_irq = mbhc->mbhc_cb->jack_detect_irq(codec);
-	else
-		jack_irq = WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT;
 
 	if (mbhc->mbhc_cfg->gpio) {
 		ret = request_threaded_irq(mbhc->mbhc_cfg->gpio_irq, NULL,
@@ -3738,13 +3717,14 @@
 		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 				    1 << 1, 1 << 1);
 
-		ret = wcd9xxx_request_irq(core_res, jack_irq,
+		ret = wcd9xxx_request_irq(core_res,
+					  mbhc->intr_ids->hs_jack_switch,
 					  wcd9xxx_mech_plug_detect_irq,
 					  "Jack Detect",
 					  mbhc);
 		if (ret)
 			pr_err("%s: Failed to request insert detect irq %d\n",
-				__func__, jack_irq);
+				__func__, mbhc->intr_ids->hs_jack_switch);
 	}
 
 	return ret;
@@ -3774,9 +3754,9 @@
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x10);
 		wcd9xxx_enable_irq(mbhc->resmgr->core_res,
-				   WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+				   mbhc->intr_ids->hph_left_ocp);
 		wcd9xxx_enable_irq(mbhc->resmgr->core_res,
-				   WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+				   mbhc->intr_ids->hph_right_ocp);
 
 		/* Initialize mechanical mbhc */
 		ret = wcd9xxx_setup_jack_detect_irq(mbhc);
@@ -4116,20 +4096,21 @@
 static int wcd9xxx_get_mbhc_cfilt_sel(struct wcd9xxx_mbhc *mbhc)
 {
 	int cfilt;
-	const struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
+	const struct wcd9xxx_micbias_setting *mb_pdata =
+		mbhc->resmgr->micbias_pdata;
 
 	switch (mbhc->mbhc_cfg->micbias) {
 	case MBHC_MICBIAS1:
-		cfilt = pdata->micbias.bias1_cfilt_sel;
+		cfilt = mb_pdata->bias1_cfilt_sel;
 		break;
 	case MBHC_MICBIAS2:
-		cfilt = pdata->micbias.bias2_cfilt_sel;
+		cfilt = mb_pdata->bias2_cfilt_sel;
 		break;
 	case MBHC_MICBIAS3:
-		cfilt = pdata->micbias.bias3_cfilt_sel;
+		cfilt = mb_pdata->bias3_cfilt_sel;
 		break;
 	case MBHC_MICBIAS4:
-		cfilt = pdata->micbias.bias4_cfilt_sel;
+		cfilt = mb_pdata->bias4_cfilt_sel;
 		break;
 	default:
 		cfilt = MBHC_MICBIAS_INVALID;
@@ -4197,10 +4178,11 @@
 			   (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
 				wcd9xxx_switch_micbias(mbhc, 1);
 			/*
-			 * Disable MBHC TxFE, in case it was enabled
-			 * earlier when micbias was enabled.
+			 * Disable MBHC TxFE, in case it was enabled earlier
+			 * when micbias was enabled and polling is not active.
 			 */
-			wcd9xxx_enable_mbhc_txfe(mbhc, false);
+			if (!mbhc->polling_active)
+				wcd9xxx_enable_mbhc_txfe(mbhc, false);
 		}
 		break;
 	/* PA usage change */
@@ -4367,13 +4349,7 @@
 	 */
 	mutex_lock(&codec->mutex);
 
-	/*
-	 * Fast(mbhc) mode bandagap doesn't need to be enabled explicitly
-	 * since fast mode is set by MBHC hardware when override is on.
-	 * Enable bandgap mode to avoid unnecessary RCO disable and enable
-	 * during clock source change.
-	 */
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
+	wcd9xxx_onoff_ext_mclk(mbhc, true);
 
 	wcd9xxx_turn_onoff_override(mbhc, true);
 	pr_debug("%s: Setting impedance detection\n", __func__);
@@ -4421,7 +4397,7 @@
 
 	mutex_unlock(&codec->mutex);
 
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
+	wcd9xxx_onoff_ext_mclk(mbhc, false);
 
 	wcd9xxx_turn_onoff_override(mbhc, false);
 	mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
@@ -4460,7 +4436,9 @@
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
 		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
-		      const struct wcd9xxx_mbhc_cb *mbhc_cb, int rco_clk_rate,
+		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
+		      const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
+		      int rco_clk_rate,
 		      bool impedance_det_en)
 {
 	int ret;
@@ -4487,8 +4465,13 @@
 	mbhc->micbias_enable_cb = micbias_enable_cb;
 	mbhc->rco_clk_rate = rco_clk_rate;
 	mbhc->mbhc_cb = mbhc_cb;
+	mbhc->intr_ids = mbhc_cdc_intr_ids;
 	mbhc->impedance_detect = impedance_det_en;
-	impedance_detect_en = impedance_det_en ? 1 : 0;
+
+	if (mbhc->intr_ids == NULL) {
+		pr_err("%s: Interrupt mapping not provided\n", __func__);
+		return -EINVAL;
+	}
 
 	if (mbhc->headset_jack.jack == NULL) {
 		ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
@@ -4532,63 +4515,71 @@
 
 	wcd9xxx_init_debugfs(mbhc);
 
+
+	/* Disable Impedance detection by default for certain codec types */
+	if (mbhc->mbhc_cb &&
+	    mbhc->mbhc_cb->get_cdc_type() == WCD9XXX_CDC_TYPE_HELICON)
+		impedance_detect_en = 0;
+	else
+		impedance_detect_en = impedance_det_en ? 1 : 0;
+
 	core_res = mbhc->resmgr->core_res;
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
+	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->insertion,
 				  wcd9xxx_hs_insert_irq,
 				  "Headset insert detect", mbhc);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
-		       WCD9XXX_IRQ_MBHC_INSERTION, ret);
+		       mbhc->intr_ids->insertion, ret);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, mbhc->intr_ids->insertion);
 
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL,
+	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->poll_plug_rem,
 				  wcd9xxx_hs_remove_irq,
 				  "Headset remove detect", mbhc);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
-			WCD9XXX_IRQ_MBHC_REMOVAL);
+			mbhc->intr_ids->poll_plug_rem);
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->dce_est_complete,
 				  wcd9xxx_dce_handler, "DC Estimation detect",
 				  mbhc);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_MBHC_POTENTIAL);
+		       mbhc->intr_ids->dce_est_complete);
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->button_release,
 				  wcd9xxx_release_handler,
 				  "Button Release detect", mbhc);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
-			WCD9XXX_IRQ_MBHC_RELEASE);
+			mbhc->intr_ids->button_release);
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->hph_left_ocp,
 				  wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
 				  mbhc);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+		       mbhc->intr_ids->hph_left_ocp);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(core_res, mbhc->intr_ids->hph_left_ocp);
 
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->hph_right_ocp,
 				  wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
 				  mbhc);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+		       mbhc->intr_ids->hph_right_ocp);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, mbhc->intr_ids->hph_right_ocp);
 
 	wcd9xxx_regmgr_cond_register(resmgr, 1 << WCD9XXX_COND_HPH_MIC |
 					     1 << WCD9XXX_COND_HPH);
@@ -4597,15 +4588,15 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_left_ocp, mbhc);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->button_release, mbhc);
 err_release_irq:
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->dce_est_complete, mbhc);
 err_potential_irq:
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->poll_plug_rem, mbhc);
 err_remove_irq:
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->insertion, mbhc);
 err_insert_irq:
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
@@ -4622,22 +4613,15 @@
 	wcd9xxx_regmgr_cond_deregister(mbhc->resmgr, 1 << WCD9XXX_COND_HPH_MIC |
 						     1 << WCD9XXX_COND_HPH);
 
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->free_irq)
-		mbhc->mbhc_cb->free_irq(mbhc);
-	else
-		wcd9xxx_free_irq(core_res, WCD9320_IRQ_MBHC_JACK_SWITCH,
-				 mbhc);
-
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->button_release, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->dce_est_complete, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->poll_plug_rem, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->insertion, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hs_jack_switch, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_left_ocp, mbhc);
+	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_right_ocp, mbhc);
 
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
-
 	wcd9xxx_cleanup_debugfs(mbhc);
 }
 EXPORT_SYMBOL(wcd9xxx_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 91280e4..9d0afe9 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -236,16 +236,26 @@
 	u8 reg_mask;
 };
 
+struct wcd9xxx_mbhc_intr {
+	int poll_plug_rem;
+	int shortavg_complete;
+	int potential_button_press;
+	int button_release;
+	int dce_est_complete;
+	int insertion;
+	int hph_left_ocp;
+	int hph_right_ocp;
+	int hs_jack_switch;
+};
+
 struct wcd9xxx_mbhc_cb {
 	void (*enable_mux_bias_block) (struct snd_soc_codec *);
 	void (*cfilt_fast_mode) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
 	void (*codec_specific_cal) (struct snd_soc_codec *,
 				    struct wcd9xxx_mbhc *);
-	int (*jack_detect_irq) (struct snd_soc_codec *);
 	struct wcd9xxx_cfilt_mode (*switch_cfilt_mode) (struct wcd9xxx_mbhc *,
 							bool);
 	void (*select_cfilt) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
-	void (*free_irq) (struct wcd9xxx_mbhc *);
 	enum wcd9xxx_cdc_type (*get_cdc_type) (void);
 	void (*enable_clock_gate) (struct snd_soc_codec *, bool);
 	int (*setup_zdet) (struct wcd9xxx_mbhc *,
@@ -327,6 +337,9 @@
 
 	bool update_z;
 
+	/* Holds codec specific interrupt mapping */
+	const struct wcd9xxx_mbhc_intr *intr_ids;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
@@ -395,6 +408,7 @@
 		      struct snd_soc_codec *codec,
 		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
 		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
+		      const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
 		      int rco_clk_rate,
 		      bool impedance_det_en);
 void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index cb76342..5d74469 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -561,6 +561,8 @@
 		if (--resmgr->clk_rco_users == 0 &&
 		    resmgr->clk_type == WCD9XXX_CLK_RCO) {
 			wcd9xxx_disable_clock_block(resmgr);
+			snd_soc_update_bits(resmgr->codec,
+					WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x00);
 			resmgr->clk_type = WCD9XXX_CLK_OFF;
 		}
 		break;
@@ -658,7 +660,7 @@
 			     unsigned int cfilt_mv)
 {
 	int rc = -EINVAL;
-	unsigned int ldoh_v = resmgr->pdata->micbias.ldoh_v;
+	unsigned int ldoh_v = resmgr->micbias_pdata->ldoh_v;
 	unsigned min_mv, max_mv;
 
 	switch (ldoh_v) {
@@ -843,6 +845,7 @@
 			struct snd_soc_codec *codec,
 			struct wcd9xxx_core_resource *core_res,
 			struct wcd9xxx_pdata *pdata,
+			struct wcd9xxx_micbias_setting *micbias_pdata,
 			struct wcd9xxx_reg_address *reg_addr,
 			enum wcd9xxx_cdc_type cdc_type)
 {
@@ -856,6 +859,7 @@
 	/* This gives access of core handle to lock/unlock suspend */
 	resmgr->core_res = core_res;
 	resmgr->pdata = pdata;
+	resmgr->micbias_pdata = micbias_pdata;
 	resmgr->reg_addr = reg_addr;
 
 	INIT_LIST_HEAD(&resmgr->update_bit_cond_h);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 7fb5820..603bd1e 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -137,6 +137,8 @@
 
 	struct wcd9xxx_pdata *pdata;
 
+	struct wcd9xxx_micbias_setting *micbias_pdata;
+
 	struct blocking_notifier_head notifier;
 	/* Notifier needs mbhc pointer with resmgr */
 	struct wcd9xxx_mbhc *mbhc;
@@ -162,6 +164,7 @@
 			struct snd_soc_codec *codec,
 			struct wcd9xxx_core_resource *core_res,
 			struct wcd9xxx_pdata *pdata,
+			struct wcd9xxx_micbias_setting *micbias_pdata,
 			struct wcd9xxx_reg_address *reg_addr,
 			enum wcd9xxx_cdc_type cdc_type);
 void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr);
diff --git a/sound/soc/msm/msm-pcm-hostless.c b/sound/soc/msm/msm-pcm-hostless.c
index 789749f..0f3573b 100644
--- a/sound/soc/msm/msm-pcm-hostless.c
+++ b/sound/soc/msm/msm-pcm-hostless.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,21 @@
 #include <sound/soc.h>
 #include <sound/pcm.h>
 
-static struct snd_pcm_ops msm_pcm_hostless_ops = {};
+
+static int msm_pcm_hostless_prepare(struct snd_pcm_substream *substream)
+{
+	if (!substream) {
+		pr_err("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	if (pm_qos_request_active(&substream->latency_pm_qos_req))
+		pm_qos_remove_request(&substream->latency_pm_qos_req);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_hostless_ops = {
+	.prepare = msm_pcm_hostless_prepare
+};
 
 static struct snd_soc_platform_driver msm_soc_hostless_platform = {
 	.ops		= &msm_pcm_hostless_ops,
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 40de65b..6cd7383 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -688,6 +688,22 @@
 	return 0;
 }
 
+static int msm_be_fm_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;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
 static const struct soc_enum msm_snd_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
@@ -1369,7 +1385,7 @@
 		.codec_dai_name = "msm-stub-rx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_be_fm_hw_params_fixup,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index e612eec..d7ddca2 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1377,6 +1377,22 @@
 	return 0;
 }
 
+static int msm_be_fm_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;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
 static const struct soc_enum msm_snd_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
@@ -2262,7 +2278,7 @@
 		.codec_dai_name = "msm-stub-rx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_be_fm_hw_params_fixup,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index c318849..a1b06da 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -74,6 +74,9 @@
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
 	.use_int_rbias = false,
+	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+			    1 << MBHC_CS_ENABLE_INSERTION |
+			    1 << MBHC_CS_ENABLE_REMOVAL),
 };
 
 /*
@@ -210,6 +213,22 @@
 	return 0;
 }
 
+static int msm_be_fm_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;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
 static int msm_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				struct snd_pcm_hw_params *params)
 {
@@ -538,7 +557,7 @@
 #undef S
 #define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(msm8x10_wcd_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1650);
+	S(v_hs_max, 2550);
 #undef S
 #define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
 	S(c[0], 62);
@@ -902,7 +921,7 @@
 		.codec_dai_name = "msm-stub-rx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_INT_FM_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_be_fm_hw_params_fixup,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 094c58b..d23eee1 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -1519,7 +1519,8 @@
 
 	/* get the cvs cal data */
 	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVS_CAL_SIZE)
 		goto fail;
 
 	if (v == NULL) {
@@ -1594,7 +1595,8 @@
 	u16 cvs_handle;
 
 	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVS_CAL_SIZE)
 		return 0;
 
 	if (v == NULL) {
@@ -1646,7 +1648,8 @@
 	struct acdb_cal_block cal_block;
 	/* get all cvp cal data */
 	get_all_cvp_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVP_CAL_SIZE)
 		goto fail;
 
 	if (is_volte_session(v->session_id) ||
@@ -1787,7 +1790,8 @@
 
 	/* get all cvs cal data */
 	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVS_CAL_SIZE)
 		goto fail;
 
 	if (v == NULL) {
@@ -1859,7 +1863,8 @@
 	uint32_t cal_paddr = 0;
 
 	get_all_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVS_CAL_SIZE)
 		return 0;
 
 	if (v == NULL) {
@@ -1928,7 +1933,8 @@
 
       /* get the cvp cal data */
 	get_all_vocproc_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVP_CAL_SIZE)
 		goto fail;
 
 	if (v == NULL) {
@@ -2003,7 +2009,8 @@
 	u16 cvp_handle;
 
 	get_all_vocproc_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size > CVP_CAL_SIZE)
 		return 0;
 
 	if (v == NULL) {
@@ -2053,6 +2060,7 @@
 	struct cvp_register_vol_cal_table_cmd cvp_reg_cal_tbl_cmd;
 	struct acdb_cal_block vol_block;
 	struct acdb_cal_block voc_block;
+	struct acdb_cal_block cvp_block;
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
@@ -2062,8 +2070,10 @@
 	/* get the cvp vol cal data */
 	get_all_vocvol_cal(&vol_block);
 	get_all_vocproc_cal(&voc_block);
+	get_all_cvp_cal(&cvp_block);
 
-	if (vol_block.cal_size == 0)
+	if (vol_block.cal_size == 0 ||
+	    cvp_block.cal_size > CVP_CAL_SIZE)
 		goto fail;
 
 	if (v == NULL) {
@@ -2135,12 +2145,16 @@
 {
 	struct cvp_deregister_vol_cal_table_cmd cvp_dereg_cal_tbl_cmd;
 	struct acdb_cal_block cal_block;
+	struct acdb_cal_block voc_block;
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
 
 	get_all_vocvol_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	get_all_cvp_cal(&voc_block);
+
+	if (cal_block.cal_size == 0 ||
+	    voc_block.cal_size > CVP_CAL_SIZE)
 		return 0;
 
 	if (v == NULL) {
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 93defcd..01422cf 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -1508,7 +1508,7 @@
 static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int result = 0;
-	int size = vma->vm_end - vma->vm_start;
+	uint32_t size = vma->vm_end - vma->vm_start;
 
 	pr_debug("%s\n", __func__);
 
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index bedaba0..93b3597 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -454,6 +454,15 @@
 
 			}
 
+			if (test_bit_pos(audio_ocmem_lcl.audio_state,
+						OCMEM_STATE_DISABLE) ||
+			    test_bit_pos(audio_ocmem_lcl.audio_state,
+			     OCMEM_STATE_FREE)) {
+				pr_info("%s: audio already freed from ocmem, state[0x%x]\n",
+					__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state));
+				goto fail_cmd2;
+			}
 			pr_debug("%s: calling ocmem free, state:0x%x\n",
 				__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
@@ -491,7 +500,11 @@
 				ret);
 				goto fail_cmd2;
 			}
-			pr_debug("%s: ocmem_free success\n", __func__);
+			set_bit_pos(audio_ocmem_lcl.audio_state,
+					OCMEM_STATE_FREE);
+			pr_debug("%s: ocmem_free success, state[0x%x]\n",
+				 __func__,
+				 atomic_read(&audio_ocmem_lcl.audio_state));
 		/* Fall through */
 		case OCMEM_STATE_SSR:
 			msm_bus_scale_client_update_request(
@@ -517,6 +530,8 @@
 	ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
 	if (ret)
 		pr_err("%s: ocmem_free failed\n", __func__);
+	set_bit_pos(audio_ocmem_lcl.audio_state,
+		    OCMEM_STATE_FREE);
 fail_cmd2:
 	mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 fail_cmd:
@@ -710,7 +725,8 @@
 			audio_ocmem_lcl.ocmem_en = true;
 	}
 
-	if (audio_ocmem_lcl.ocmem_en) {
+	if (audio_ocmem_lcl.ocmem_en &&
+	    (!enable || !audio_ocmem_lcl.audio_ocmem_running)) {
 		if (audio_ocmem_lcl.audio_ocmem_workqueue == NULL) {
 			pr_err("%s: audio ocmem workqueue is NULL\n",
 								__func__);
@@ -875,7 +891,7 @@
 			create_ramdump_device("audio-ocmem", &pdev->dev);
 
 		if (!audio_ocmem_lcl.ocmem_ramdump_dev)
-			pr_err("%s: audio-ocmem ramdump device failed\n",
+			pr_info("%s: audio-ocmem ramdump device failed\n",
 				__func__);
 	} else {
 		pr_err("%s: ocmem dump memory alloc failed\n", __func__);
@@ -887,16 +903,18 @@
 	if (!audio_ocmem_lcl.audio_ocmem_workqueue) {
 		pr_err("%s: Failed to create ocmem audio work queue\n",
 			__func__);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto destroy_ramdump;
 	}
 
 	audio_ocmem_lcl.voice_ocmem_workqueue =
 		alloc_workqueue("ocmem_audio_client_driver_voice",
 					WQ_NON_REENTRANT, 0);
 	if (!audio_ocmem_lcl.voice_ocmem_workqueue) {
-		pr_err("%s: Failed to create ocmem voice work queue\n",
+		pr_info("%s: Failed to create ocmem voice work queue\n",
 			__func__);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto destroy_audio_wq;
 	}
 
 	init_waitqueue_head(&audio_ocmem_lcl.audio_wait);
@@ -913,7 +931,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "%s: failed to populate platform data, rc = %d\n",
 						__func__, ret);
-		return -ENODEV;
+		goto destroy_voice_wq;
 	}
 	audio_ocmem_bus_scale_pdata = dev_get_drvdata(&pdev->dev);
 
@@ -923,7 +941,8 @@
 	if (!audio_ocmem_lcl.audio_ocmem_bus_client) {
 		pr_err("%s: msm_bus_scale_register_client() failed\n",
 		__func__);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto destroy_voice_wq;
 	}
 	audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
 						&audio_ocmem_client_nb);
@@ -933,6 +952,23 @@
 	}
 	audio_ocmem_lcl.lp_memseg_ptr = NULL;
 	return 0;
+destroy_voice_wq:
+	if (audio_ocmem_lcl.voice_ocmem_workqueue) {
+		destroy_workqueue(audio_ocmem_lcl.voice_ocmem_workqueue);
+		audio_ocmem_lcl.voice_ocmem_workqueue = NULL;
+	}
+destroy_audio_wq:
+	if (audio_ocmem_lcl.audio_ocmem_workqueue) {
+		destroy_workqueue(audio_ocmem_lcl.audio_ocmem_workqueue);
+		audio_ocmem_lcl.audio_ocmem_workqueue = NULL;
+	}
+destroy_ramdump:
+	if (audio_ocmem_lcl.ocmem_ramdump_dev)
+		destroy_ramdump_device(audio_ocmem_lcl.ocmem_ramdump_dev);
+	if (audio_ocmem_lcl.ocmem_dump_addr)
+		free_contiguous_memory_by_paddr(
+		    audio_ocmem_lcl.ocmem_dump_addr);
+	return ret;
 }
 
 static int ocmem_audio_client_remove(struct platform_device *pdev)
@@ -945,7 +981,12 @@
 	msm_bus_cl_clear_pdata(audio_ocmem_bus_scale_pdata);
 	ocmem_notifier_unregister(audio_ocmem_lcl.audio_hdl,
 					&audio_ocmem_client_nb);
-	free_contiguous_memory_by_paddr(audio_ocmem_lcl.ocmem_dump_addr);
+	if (audio_ocmem_lcl.ocmem_ramdump_dev)
+		destroy_ramdump_device(audio_ocmem_lcl.ocmem_ramdump_dev);
+	if (audio_ocmem_lcl.ocmem_dump_addr)
+		free_contiguous_memory_by_paddr(
+		    audio_ocmem_lcl.ocmem_dump_addr);
+
 	return 0;
 }
 static const struct of_device_id msm_ocmem_audio_dt_match[] = {
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
old mode 100644
new mode 100755
index aa6ef6b..a632644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -51,6 +51,8 @@
 #define COMPRE_OUTPUT_METADATA_SIZE	(sizeof(struct output_meta_data_st))
 #define COMPRESSED_LR_VOL_MAX_STEPS	0x20002000
 
+#define MAX_AC3_PARAM_SIZE		(18*2*sizeof(int))
+
 const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
 			    COMPRESSED_LR_VOL_MAX_STEPS);
 struct snd_msm {
@@ -977,19 +979,25 @@
 			compr->codec = FORMAT_MPEG4_AAC;
 			break;
 		case SND_AUDIOCODEC_AC3: {
-			char params_value[18*2*sizeof(int)];
+			char params_value[MAX_AC3_PARAM_SIZE];
 			int *params_value_data = (int *)params_value;
 			/* 36 is the max param length for ddp */
 			int i;
 			struct snd_dec_ddp *ddp =
 				&compr->info.codec_param.codec.options.ddp;
-			int params_length = ddp->params_length*sizeof(int);
+			uint32_t params_length = ddp->params_length*sizeof(int);
+			if(params_length > MAX_AC3_PARAM_SIZE) {
+				/*MAX is 36*sizeof(int) this should not happen*/
+				pr_err("params_length(%d) is greater than %d",
+				params_length, MAX_AC3_PARAM_SIZE);
+				params_length = MAX_AC3_PARAM_SIZE;
+			}
 			pr_debug("SND_AUDIOCODEC_AC3\n");
 			compr->codec = FORMAT_AC3;
 			if (copy_from_user(params_value, (void *)ddp->params,
 					params_length))
-				pr_err("%s: ERROR: copy ddp params value\n",
-					__func__);
+				pr_err("%s: copy ddp params value, size=%d\n",
+					__func__, params_length);
 			pr_debug("params_length: %d\n", ddp->params_length);
 			for (i = 0; i < params_length; i++)
 				pr_debug("params_value[%d]: %x\n", i,
@@ -1008,19 +1016,25 @@
 			break;
 		}
 		case SND_AUDIOCODEC_EAC3: {
-			char params_value[18*2*sizeof(int)];
+			char params_value[MAX_AC3_PARAM_SIZE];
 			int *params_value_data = (int *)params_value;
 			/* 36 is the max param length for ddp */
 			int i;
 			struct snd_dec_ddp *ddp =
 				&compr->info.codec_param.codec.options.ddp;
-			int params_length = ddp->params_length*sizeof(int);
+			uint32_t params_length = ddp->params_length*sizeof(int);
+			if(params_length > MAX_AC3_PARAM_SIZE) {
+				/*MAX is 36*sizeof(int) this should not happen*/
+				pr_err("params_length(%d) is greater than %d",
+				params_length, MAX_AC3_PARAM_SIZE);
+				params_length = MAX_AC3_PARAM_SIZE;
+			}
 			pr_debug("SND_AUDIOCODEC_EAC3\n");
 			compr->codec = FORMAT_EAC3;
 			if (copy_from_user(params_value, (void *)ddp->params,
 					params_length))
-				pr_err("%s: ERROR: copy ddp params value\n",
-					__func__);
+				pr_err("%s: copy ddp params value, size=%d\n",
+					__func__, params_length);
 			pr_debug("params_length: %d\n", ddp->params_length);
 			for (i = 0; i < ddp->params_length; i++)
 				pr_debug("params_value[%d]: %x\n", i,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 59113fe..09ecd75 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -648,7 +648,7 @@
 		ret = get_hw_delay(RX_CAL, &delay_entry);
 
 	if (ret != 0) {
-		pr_warn("%s: Failed to get hw delay info\n", __func__);
+		pr_debug("%s: Failed to get hw delay info\n", __func__);
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(port_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 9c0c362..7c4547e 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -78,6 +78,12 @@
 void *q6asm_mmap_apr_reg(void);
 
 
+/* for ASM custom topology */
+static struct audio_buffer common_buf[2];
+static struct audio_client common_client;
+static int set_custom_topology;
+static int topology_map_handle;
+
 #ifdef CONFIG_DEBUG_FS
 #define OUT_BUFFER_SIZE 56
 #define IN_BUFFER_SIZE 24
@@ -95,10 +101,6 @@
 static int out_cold_index;
 static char *out_buffer;
 static char *in_buffer;
-static struct audio_buffer common_buf[2];
-static struct audio_client common_client;
-static int set_custom_topology;
-static int topology_map_handle;
 
 
 int q6asm_mmap_apr_dereg(void)
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index c16b14c..673ecff 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1958,20 +1958,22 @@
 	if (!common.apr_q6_cvs) {
 		pr_err("%s: apr_cvs is NULL\n", __func__);
 
-		ret = -EPERM;
+		ret = -EINVAL;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
 		pr_err("%s: Cal mem handle is NULL\n", __func__);
-		ret = -EPERM;
+
+		ret = -EINVAL;
 		goto done;
 	}
 
 	get_vocstrm_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVS cal size is 0\n", __func__);
-		ret = -EPERM;
+
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -1992,6 +1994,15 @@
 
 	/* Get the column info corresponding to CVS cal from ACDB. */
 	get_voice_col_data(VOCSTRM_CAL, &cal_block);
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size >
+	    sizeof(cvs_reg_cal_cmd.cvs_cal_data.column_info)) {
+		pr_err("%s: Invalid VOCSTRM_CAL size %d\n",
+		       __func__, cal_block.cal_size);
+
+		ret = -EINVAL;
+		goto done;
+	}
 	memcpy(&cvs_reg_cal_cmd.cvs_cal_data.column_info[0],
 	       (void *) cal_block.cal_kvaddr,
 	       cal_block.cal_size);
@@ -2238,20 +2249,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EPERM;
+		ret = -EINVAL;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
 		pr_err("%s: Cal mem handle is NULL\n", __func__);
-		ret = -EPERM;
+
+		ret = -EINVAL;
 		goto done;
 	}
 
 	get_vocproc_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP cal size is 0\n", __func__);
-		ret = -EPERM;
+
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2272,6 +2285,16 @@
 
 	/* Get the column info corresponding to CVP cal from ACDB. */
 	get_voice_col_data(VOCPROC_CAL, &cal_block);
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size >
+	    sizeof(cvp_reg_cal_cmd.cvp_cal_data.column_info)) {
+		pr_err("%s: Invalid VOCPROC_CAL size %d\n",
+		       __func__, cal_block.cal_size);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
 	memcpy(&cvp_reg_cal_cmd.cvp_cal_data.column_info[0],
 	       (void *) cal_block.cal_kvaddr,
 	       cal_block.cal_size);
@@ -2378,20 +2401,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EPERM;
+		ret = -EINVAL;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
 		pr_err("%s: Cal mem handle is NULL\n", __func__);
-		ret = -EPERM;
+
+		ret = -EINVAL;
 		goto done;
 	}
 
 	get_vocvol_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP vol cal size is 0\n", __func__);
-		ret = -EPERM;
+
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2414,6 +2439,16 @@
 
 	/* Get the column info corresponding to CVP volume cal from ACDB. */
 	get_voice_col_data(VOCVOL_CAL, &cal_block);
+	if (cal_block.cal_size == 0 ||
+	    cal_block.cal_size >
+	    sizeof(cvp_reg_vol_cal_cmd.cvp_vol_cal_data.column_info)) {
+		pr_err("%s: Invalid VOCVOL_CAL size %d\n",
+		       __func__, cal_block.cal_size);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
 	memcpy(&cvp_reg_vol_cal_cmd.cvp_vol_cal_data.column_info[0],
 	       (void *) cal_block.cal_kvaddr,
 	       cal_block.cal_size);