Merge "ASoC: msm: qdsp6v2: Fix buffer overflow in voice driver"
diff --git a/Documentation/bif-framework.txt b/Documentation/bif-framework.txt
index 3ba500d..9831c80 100644
--- a/Documentation/bif-framework.txt
+++ b/Documentation/bif-framework.txt
@@ -235,10 +235,10 @@
 Get/put handle for a BIF slave:
 -------------------------------
 
-int bif_slave_match_count(const struct bif_ctrl *ctrl,
+int bif_slave_match_count(struct bif_ctrl *ctrl,
 			const struct bif_match_criteria *match_criteria);
 
-struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
 	unsigned int id, const struct bif_match_criteria *match_criteria);
 
 void bif_slave_put(struct bif_slave *slave);
@@ -293,7 +293,6 @@
 int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
 				struct notifier_block *nb);
 
-
 Read or write BIF slave registers:
 ----------------------------------
 
@@ -302,6 +301,53 @@
 int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
 
 
+BIF slave non-volatile memory manipulation:
+-------------------------------------------
+
+int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
+				int len);
+
+int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
+				int len);
+
+Raw NVM writing may be needed in order to intialize the NVM BIF object list.
+However, its use can be dangerous as it can overwrite existing objects in the
+list and make the list unparsable.
+
+BIF object search in slave non-volatile memory:
+-----------------------------------------------
+int bif_object_match_count(struct bif_slave *slave,
+			const struct bif_obj_match_criteria *match_criteria);
+
+struct bif_object *bif_object_match_get(struct bif_slave *slave,
+	unsigned int id, const struct bif_obj_match_criteria *match_criteria);
+
+void bif_object_put(struct bif_object *object);
+
+bif_object_match_count() and bif_object_match_get() can be used together in
+order to retrieve the set of BIF objects within a slave which match certain
+criteria.  bif_object_put() is used to free the memory allocated by
+bif_object_match_get().
+
+BIF object manipulation in slave non-volatile memory:
+-----------------------------------------------------
+int bif_object_write(struct bif_slave *slave, u8 type, u8 version, u16
+			manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_overwrite(struct bif_slave *slave,
+	struct bif_object *object, u8 type, u8 version,
+	u16 manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_delete(struct bif_slave *slave, const struct bif_object *object);
+
+bif_object_write() can be used to write a new BIF data object into the NVM of
+a given slave.  The new object is added to the end of the NVM object list.
+bif_object_overwrite() can be used to overwrite an existing BIF data object
+in the NVM of a slave.  The new object data must be the same size as the
+existing object data.  bif_object_delete() can be used to delete a object from
+the NVM object list and shift all of the objects after it in order to fill the
+deleted object's space.
+
 Get or set the BIF bus state or period:
 ---------------------------------------
 
@@ -341,11 +387,17 @@
 
 int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
 
+int bif_enable_auto_task(struct bif_slave *slave, unsigned int task);
+
+int bif_disable_auto_task(struct bif_slave *slave, unsigned int task);
+
 A consumer can request a slave interrupt and specify a notifier to call when the
 interrupt is triggered.  Once the interrupt is requested the consumer will need
 to call bif_trigger_task() in order to start the task associated with the
 interrupt (both are identified by the same index).  Polling for task completion
-is also supported via the bif_task_is_busy() function.
+is also supported via the bif_task_is_busy() function.  Auto task triggered can
+be enabled and disabled for a given task using bif_enable_auto_task() and
+bif_disable_auto_task() respectively.
 
 Raw BIF bus transactions:
 -------------------------
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 4e3abc2..a0b2f6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -22,16 +22,12 @@
 				should be 1 for SVS corner
 - regulator-max-microvolt:	Maximum corner value as max constraint, which
 				should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,pvs-bin-process:		A list of integers whose length is equal to 2 to
-				the power of qcom,pvs-fuse[num-of-bits]. The location or
-				0-based index of an element in the list corresponds
-				to the bin number. The value of each integer
-				corresponds to the PVS process speed of the APC
-				silicon for a chip with one of these cases:
-					1 = APC_PVS_SLOW
-					2 = APC_PVS_NOM
-					3 = APC_PVS_FAST
-					0 or other values = No PVS
+- qcom,pvs-init-voltage:  	A list of integers whose length is equal to 2
+				to the power of qcom,pvs-fuse[num-of-bits]. The
+				location or 0-based index of an element in the
+				list corresponds to the bin number. The value of
+				each integer corresponds to the initial voltage
+				of the PVS bin in turbo mode in microvolts.
 - qcom,pvs-corner-ceiling-slow:	Ceiling voltages of all corners for APC_PVS_SLOW
 - qcom,pvs-corner-ceiling-nom:	Ceiling voltages of all corners for APC_PVS_NOM
 - qcom,pvs-corner-ceiling-fast:	Ceiling voltages of all corners for APC_PVS_FAST
@@ -155,8 +151,14 @@
 		qcom,pvs-fuse-redun-sel = <22 24 3 2>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
+						1310000 1300000 1290000 1280000
+						1270000 1260000 1250000 1240000
+						1230000 1220000 1210000 1200000
+						1190000 1180000 1170000 1160000
+						1150000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000>;
 		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
 		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index f57d928..917ea75 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -20,6 +20,7 @@
 		"pc_no_xo_shutdown" - Power Collapse with no XO shutdown
 - qcom,l2: The state of L2 cache. Values are:
 		"l2_cache_pc" - L2 cache in power collapse
+		"l2_cache_pc_no_rpm" - L2 cache in power collapse. This mode wouldn't inform the RPM
 		"l2_cache_retenetion" - L2 cache in retention
 		"l2_cache_gdhs" - L2 cache in GDHS
 		"l2_cache_active" - L2 cache in active mode
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
index 5692ad2..4a1fb59 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
@@ -38,7 +38,6 @@
 	the below optional properties:
 	- qcom,msm-bus,name
 	- qcom,msm-bus,num-cases
-	- qcom,msm-bus,active-only
 	- qcom,msm-bus,num-paths
 	- qcom,msm-bus,vectors-KBps
 
@@ -85,7 +84,6 @@
 
 		qcom,msm-bus,name = "tsif";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<82 512 0 0>, /* No vote */
diff --git a/Documentation/devicetree/bindings/arm/msm/smem.txt b/Documentation/devicetree/bindings/arm/msm/smem.txt
index a38984c..b6dcdc1 100644
--- a/Documentation/devicetree/bindings/arm/msm/smem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/smem.txt
@@ -10,6 +10,10 @@
 	     "aux-mem1", "aux-mem2", "aux-mem3", ... - optional strings to
 			identify any auxiliary shared memory regions
 
+Optional properties:
+-mpu-enabled : boolean value indicating that Memory Protection Unit based
+	security is enabled on the "smem" shared memory region
+
 [Second level nodes]
 
 qcom,smd
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-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index 7187908..cda437a 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -46,12 +46,6 @@
 - qcom,platform-te-gpio:		Specifies the gpio used for TE.
 - qcom,platform-mode-gpio:		Select video/command mode of panel through gpio when it supports
 					both modes.
-- qcom,platform-reset-sequence:		An array that lists the
-					sequence of reset gpio values and sleeps
-					Each command will have the format defined
-					as below:
-					--> Reset GPIO value
-					--> Sleep value (in ms)
 
 Example:
         mdss_dsi0: qcom,mdss_dsi@fd922800 {
@@ -77,7 +71,6 @@
 		qcom,platform-te-gpio = <&msmgpio 24 0>;
 		qcom,platform-enable-gpio = <&msmgpio 58 1>;
 		qcom,platform-mode-gpio = <&msmgpio 7 0>;
-		qcom,platform-reset-sequence = <1 25 0 20 1 10>;
 		qcom,platform-supply-entry1 {
 			qcom,supply-name = "vdd";
 			qcom,supply-min-voltage = <2800000>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 9ad8abe..1a44f5a 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -63,6 +63,10 @@
 Optional properties:
 - qcom,mdss-dsi-panel-name:		A string used as a descriptive name of the panel
 - qcom,cont-splash-enabled:		Boolean used to enable continuous splash mode.
+					If this property is specified, it is required to
+					to specify the memory reserved for the splash
+					screen using the qcom,memblock-reserve binding
+					for the framebuffer device attached to the panel.
 - qcom,mdss-dsi-panel-broadcast-mode:	Boolean used to enable broadcast mode.
 - qcom,mdss-dsi-fbc-enable:		Boolean used to enable frame buffer compression mode.
 - qcom,mdss-dsi-fbc-bpp:		Compressed bpp supported by the panel.
@@ -116,6 +120,12 @@
 					0xff = default value.
 - qcom,mdss-dsi-border-color:		Defines the border color value if border is present.
 					0 = default value.
+- qcom,mdss-dsi-pan-enable-dynamic-fps:	Boolean used to enable change in frame rate dynamically.
+- qcom,mdss-dsi-pan-fps-update:		A string that specifies when to change the frame rate.
+					"dfps_suspend_resume_mode"= FPS change request is
+						implemented during suspend/resume.
+					"dfps_immediate_clk_mode" = FPS change request is
+						implemented immediately using DSI clocks.
 - qcom,mdss-dsi-bl-pmic-control-type:	A string that specifies the implementation of backlight
 					control for this panel.
 					"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
@@ -232,6 +242,14 @@
 					in dsi controller.
 					"high" = Set GPIO to HIGH
 					"low" = Set GPIO to LOW
+- qcom,partial-update-enabled:		Boolean used to enable partial
+					panel update for command mode panels.
+- qcom,mdss-dsi-reset-sequence:		An array that lists the
+					sequence of reset gpio values and sleeps
+					Each command will have the format defined
+					as below:
+					--> Reset GPIO value
+					--> Sleep value (in ms)
 
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
@@ -315,11 +333,15 @@
 		qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00];
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
 		qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 		qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
 		qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
 		qcom,mdss-pan-physical-width-dimension = <60>;
 		qcom,mdss-pan-physical-height-dimension = <140>;
 		qcom,mdss-dsi-panel-mode-gpio-state = "low";
+		qcom,partial-update-enabled;
+		qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 829cce2..8f17a90 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -106,6 +106,8 @@
 				- "hdmi"
 
 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
@@ -163,6 +165,11 @@
 			 enabled if framebuffer size is less than max mixer
 			 width; 2) the defaut even split is enabled if frambuffer
 			 size is greater than max mixer width.
+- qcom,memblock-reserve: Specifies the memory location and the size reserved
+			 for the framebuffer used to display the splash screen.
+			 This property is required whenever the continuous splash
+			 screen feature is enabled for the corresponding
+			 framebuffer device.
 
 Example:
 	mdss_mdp: qcom,mdss_mdp@fd900000 {
@@ -172,6 +179,8 @@
 		reg-names = "mdp_phys", "vbif_phys";
 		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>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
index c563067e..398e253 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
@@ -46,6 +46,7 @@
  - focaltech,fw-delay-era-flsh-ms : specify the erase flash delay in ms for firmware upgrade
  - 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
 
 Example:
 	i2c@f9923000{
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index 3e223e6..fdba7c2 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -7,7 +7,7 @@
  - interrupt-parent	: Parent of interrupt.
  - interrupts		: Configuration of touch panel controller interrupt
 				GPIO.
- - goodix,family-id	: Family identification of the controller.
+ - goodix,product-id	: Product identification of the controller.
  - interrupt-gpios	: Interrupt gpio which is to provide interrupts to
 				host, same as "interrupts" node.
  - reset-gpios		: Reset gpio to control the reset of chip.
@@ -32,10 +32,24 @@
  - goodix,no-force-update	: To specify force update is allowed.
  - goodix,button-map	: Button map of key codes. The number of key codes
 				depend on panel.
- - goodix,cfg-data	: Touchpanel controller configuration data, ask vendor
-				to provide that. Default configuration will be
-				used if this property is not present.
-
+ - goodix,cfg-data0	: Touch screen controller config data group 0. Ask vendor
+				to provide that.
+				Driver supports maximum six config groups. If more than one
+				groups are defined, driver will select config group depending
+				on hardware configuration. If only config group 0 is defined,
+				it will be used for all hardware configurations.
+				Touch screen controller will use its onchip default config data
+				if this property is not present.
+ - goodix,cfg-data1	: Touch screen controller config data group 1. Ask vendor
+				to provide that.
+ - goodix,cfg-data2	: Touch screen controller config data group 2. Ask vendor
+				to provide that.
+ - goodix,cfg-data3	: Touch screen controller config data group 3. Ask vendor
+				to provide that.
+ - goodix,cfg-data4	: Touch screen controller config data group 4. Ask vendor
+				to provide that.
+ - goodix,cfg-data5	: Touch screen controller config data group 5. Ask vendor
+				to provide that.
 Example:
 i2c@f9927000 {
 		goodix@5d {
@@ -49,26 +63,26 @@
 			goodix,panel-coords = <0 0 720 1200>;
 			goodix,display-coords = <0 0 720 1080>;
 			goodix,button-map= <158 102 139>;
-			goodix,family-id = <0x0>;
-			goodix,cfg-data = [
-		41 D0 02 00 05 0A 05 01 01 08
-		12 58 50 41 03 05 00 00 00 00
-		00 00 00 00 00 00 00 8C 2E 0E
-		28 24 73 13 00 00 00 83 03 1D
-		40 02 00 00 00 03 64 32 00 00
-		00 1A 38 94 C0 02 00 00 00 04
-		9E 1C 00 8D 20 00 7A 26 00 6D
-		2C 00 60 34 00 60 10 38 68 00
-		F0 50 35 FF FF 27 00 00 00 00
-		00 01 1B 14 0C 14 00 00 01 00
-		00 00 00 00 00 00 00 00 00 00
-		00 00 02 04 06 08 0A 0C 0E 10
-		12 14 16 18 1A 1C FF FF FF FF
-		FF FF FF FF FF FF FF FF FF FF
-		FF FF 00 02 04 06 08 0A 0C 0F
-		10 12 13 14 16 18 1C 1D 1E 1F
-		20 21 22 24 26 28 29 2A FF FF
-		FF FF FF FF FF FF FF 22 22 22
-		22 22 22 FF 07 01];
+			goodix,product-id = "915";
+			goodix,cfg-data0 = [
+				41 D0 02 00 05 0A 05 01 01 08
+				12 58 50 41 03 05 00 00 00 00
+				00 00 00 00 00 00 00 8C 2E 0E
+				28 24 73 13 00 00 00 83 03 1D
+				40 02 00 00 00 03 64 32 00 00
+				00 1A 38 94 C0 02 00 00 00 04
+				9E 1C 00 8D 20 00 7A 26 00 6D
+				2C 00 60 34 00 60 10 38 68 00
+				F0 50 35 FF FF 27 00 00 00 00
+				00 01 1B 14 0C 14 00 00 01 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 02 04 06 08 0A 0C 0E 10
+				12 14 16 18 1A 1C FF FF FF FF
+				FF FF FF FF FF FF FF FF FF FF
+				FF FF 00 02 04 06 08 0A 0C 0F
+				10 12 13 14 16 18 1C 1D 1E 1F
+				20 21 22 24 26 28 29 2A FF FF
+				FF FF FF FF FF FF FF 22 22 22
+				22 22 22 FF 07 01];
 		};
 };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 8fd813c..4f9307a 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -18,10 +18,14 @@
  - synaptics,button-map		: virtual key code mappings to be used
  - synaptics,x-flip		: modify orientation of the x axis
  - synaptics,y-flip		: modify orientation of the y axis
- - synaptics,panel-x		: panel x dimension
- - synaptics,panel-y		: panel y dimension
+ - synaptics,panel-coords	: touch panel min x, min y, max x and
+					max y resolution
+ - synaptics,display-coords	: display min x, min y, max x and
+					max y resolution
+ - synaptics,reset-delay	: reset delay for controller (ms), default 100
  - synaptics,fw-image-name	: name of firmware .img file in /etc/firmware
  - synaptics,power-down		: fully power down regulators in suspend
+ - synaptics,do-lockdown	: perform one time lockdown procedure
 
 Example:
 	i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index c7c6415..cf21158 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -14,6 +14,7 @@
 - qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
   access to the IOMMU configuration registers
 - Bus scaling properties: See msm_bus.txt
+- qcom,msm-enable-remote-spinlock : boolean to enable use of remote spinlock
 
 - List of sub nodes, one for each of the translation context banks supported.
     Required properties for each sub-node:
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index f7e50eb..af6a0b5 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -38,10 +38,10 @@
 Flash is used primarily as a camera or video flash.
 
 Optional properties for flash:
-- qcom,headroom: headroom to use, mV
-- qcom,duration: duration of the flash, ms
+- qcom,headroom: headroom to use. Values should be 0, 1, 2, 3 for 250mV, 300mV, 400mV and 500mV
+- qcom,duration: duration of the flash and torch, 10ms - 1280ms for flash and 2s - 33s for torch
 - qcom,clamp-curr: current to clamp at, mA
-- qcom,startup-dly: delay before flashing after flash executed, us
+- qcom,startup-dly: delay before flashing after flash executed. Values should 0, 1, 2, 3 for 10us, 32us, 64us, and 128us
 - qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index c60441f..317c078 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -49,6 +49,7 @@
 Required properties:
 - compatible : should be manufacturer name followed by sensor name
     - "qcom,s5k3l1yx"
+    - "sne,imx134"
     - "qcom,imx135"
     - "shinetech,gc0339"
     - "shinetech,hi256"
diff --git a/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
new file mode 100644
index 0000000..cef9cf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
@@ -0,0 +1,9 @@
+OmniVision Image Sensor Device Tree Bindings.
+========================================
+
+Boards with the OmniVision Image Sensor shall have the following properties:
+
+Required root node properties:
+    - compatible:
+    - "ovti,ov8865" : OmniVision OV8865 8 megapixel Image Sensor.
+    - "ovti,ov5648" : OmniVision OV5648 5 megapixel Image Sensor.
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index f70d90f..cdd1e68 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -8,6 +8,8 @@
 - reg: NCI i2c slave address.
 - qcom,dis-gpio: specific gpio for hardware reset.
 - qcom,irq-gpio: specific gpio for read interrupt.
+- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", ...)
+- qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio
 - interrupt-parent: Should be phandle for the interrupt controller
                     that services interrupts for this device.
 - interrupts: should contain the NFC interrupt. NFC has one read interrupt.
@@ -21,6 +23,8 @@
 		reg = <0x0e>;
 		qcom,irq-gpio = <&msmgpio 21 0x00>;
 		qcom,dis-gpio = <&msmgpio 20 0x00>;
+		qcom,clk-src = "BBCLK2";
+		qcom,clk-en-gpio = <&msmgpio 0 0x00>;
 		interrupt-parent = <&msmgpio>;
 		interrupts = <21 0>;
 		qcom,clk-gpio = <&pm8226_gpios 3 0>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index b1c4ebb..5425c92 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -37,6 +37,9 @@
 - qcom,maxinput-usb-ma:			Maximum input current USB.
 - qcom,maxinput-dc-ma:			Maximum input current DC.
 - qcom,vbatdet-delta-mv:		Battery charging resume delta.
+- qcom,vbatweak-mv:			Weak battery voltage threshold in mV, above which
+					fast charging can start. The supported voltage range is
+					from 2100mV to 3600mV with a step size of 100mV.
 - qcom,charging-disabled:		Set this property to disable charging
 					by default. This can then be overriden
 					writing the the module parameter
@@ -86,6 +89,10 @@
 					that exhibit inaccuracies in battery current readings. This
 					phandle is used to check the version of the PMIC and apply
 					necessary software workarounds.
+- qcom,ovp-monitor-en			The ovp is enabled on hw by default. If this flag is
+					set, the charger ovp status is monitored in software.
+- qcom,ext-ovp-present			Indicates if an external OVP exists which reduces the
+					overall input resistance of the charge path.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
@@ -200,6 +207,7 @@
 		qcom,ibatmax-ma = <1500>;
 		qcom,ibatterm-ma = <200>;
 		qcom,ibatsafe-ma = <1500>;
+		qcom,vbatweak-mv = <3200>;
 		qcom,thermal-mitigation = <1500 700 600 325>;
 		qcom,cool-bat-degc = <10>;
 		qcom,cool-bat-mv = <4100>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 6e4f7fc..5e686a4f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -436,6 +436,8 @@
 - qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
 - qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
 			    codec.
+- qcom,mbhc-bias-internal: Flag to indicate if internal micbias should be used
+			   for headset detection.
 
 * APQ8074 ASoC Machine driver
 
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 7ca741c..24f21b4 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -7,7 +7,8 @@
 - interrupt-names : Required interrupt resource entries are:
 	"core_irq" : Interrupt for HSIC core
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
+  Required "supply-name" is either "hsic_vdd_dig" or "HSIC_VDDCX" and
+  optionally - "HSIC_GDSC".
 
 Optional properties :
 - interrupt-parent - This must provide reference to the current
@@ -81,6 +82,9 @@
   the reset and enumeration. Since some devices might take more than 100ms
   for initialization when receiving the bus reset, add delay to avoid the
   problem that enmueration is before device initialization done.
+- hsic,vdd-voltage-level: This property must be a list of three integer
+  values (no, min, max) where each value represents either a voltage in
+  microvolts or a value corresponding to voltage corner
 
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
   below optional properties:
@@ -104,7 +108,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8019_l12>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -113,6 +117,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		hsic,consider-ipa-handshake;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 44ed2dc..e7eae76 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -130,7 +130,8 @@
 - interrupt-names : Required interrupt resource entries are:
             HSUSB EHCI expects "core_irq" and optionally "async_irq".
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+  Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+  "HSUSB_1p8-supply" "HSUSB_3p3-supply".
 - qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
 
 Optional properties :
@@ -138,6 +139,15 @@
 - qcom,resume-gpio: if present then peripheral connected to usb controller
   cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
   gpio to wakeup peripheral.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+  values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+  either a voltage in microvolts or a value corresponding to voltage corner.
+  First value represents value to vote when USB is not at all active, second
+  value represents value to vote when target is not connected to dock during low
+  power mode, third value represents vlaue to vote when target is connected to dock
+  and no peripheral connected over dock during low power mode, fourth value represents
+  minimum value to vote when USB is operational, fifth item represents maximum value
+  to vote for USB is operational.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
@@ -145,11 +155,12 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8841_s2>;
+		hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
 		qcom,usb2-enable-hsphy2;
 		qcom,usb2-power-budget = <500>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
 	};
 
 ANDROID USB:
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 9fd3afe..35e7324 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -36,6 +36,7 @@
 nintendo	Nintendo
 nvidia	NVIDIA
 nxp	NXP Semiconductors
+ovti	OmniVision Technologies, Inc.
 picochip	Picochip Ltd
 powervr	Imagination Technologies
 qcom	Qualcomm, Inc.
@@ -44,6 +45,7 @@
 samsung	Samsung Semiconductor
 sbs	Smart Battery System
 schindler	Schindler
+sne	Sony
 stk	Sensortek Technology Corporation.(formerly Sitronix Technology Co., Ltd.)
 shinetech	Shine Tech Corporation, Ltd.
 sil	Silicon Image
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index d0bbc47..5201827 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -20,6 +20,7 @@
 - gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
 - qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
 - qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs.
 
 Optional properties:
 - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
@@ -49,4 +50,5 @@
                 <&msmgpio 39 0>, <&msmgpio 40 0>;
         qcom,has-48mhz-xo;
         qcom,has-pronto-hw;
+        qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
     };
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index a419f5e..8a20b47 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -26,6 +26,7 @@
 - boot_reason		     [ ARM only ]
 - callhome		     [ S390 only ]
 - cap_last_cap
+- cold_boot		     [ ARM only ]
 - core_pattern
 - core_pipe_limit
 - core_uses_pid
@@ -176,6 +177,16 @@
 Highest valid capability of the running kernel.  Exports
 CAP_LAST_CAP from the kernel.
 
+===============================================================
+
+cold_boot
+
+ARM -- indicator for system cold boot
+
+A single bit will be set in the unsigned integer value to identify
+whether the device was booted from a cold or warm state. Zero
+indicating a warm boot and one indicating a cold boot.
+
 ==============================================================
 
 core_pattern:
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 58fc698..adcf168 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -222,7 +222,8 @@
 	default DRAM_BASE if REMAP_VECTORS_TO_RAM
 	default 0x00000000
 	help
-	  The base address of exception vectors.
+	  The base address of exception vectors.  This must be two pages
+	  in size.
 
 config ARM_PATCH_PHYS_VIRT
 	bool "Patch physical to virtual translations at runtime" if EMBEDDED
@@ -1854,6 +1855,11 @@
 
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
+	depends on ENABLE_VMALLOC_SAVING=n
+
+config ENABLE_VMALLOC_SAVING
+	def_bool n
+	depends on DONT_MAP_HOLE_AFTER_MEMBANK0=n
 
 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 46f5f22..8afd986 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 {
@@ -84,7 +87,7 @@
 				1 &intc 0 148 0
 				2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -92,6 +95,7 @@
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
 			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
@@ -669,3 +673,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/apq8074-v1-ion.dtsi b/arch/arm/boot/dts/apq8074-v1-ion.dtsi
new file mode 100644
index 0000000..49d7ee1
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v1-ion.dtsi
@@ -0,0 +1,22 @@
+/* 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.
+ */
+
+&soc {
+	qcom,ion {
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/apq8074-v1.dtsi b/arch/arm/boot/dts/apq8074-v1.dtsi
index c4e7b7c..59e7f7f 100644
--- a/arch/arm/boot/dts/apq8074-v1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v1.dtsi
@@ -17,6 +17,7 @@
  */
 
 /include/ "msm8974-v1.dtsi"
+/include/ "apq8074-v1-ion.dtsi"
 
 &soc {
 	qcom,qseecom@a700000 {
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
new file mode 100644
index 0000000..49d7ee1
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.0-1-ion.dtsi
@@ -0,0 +1,22 @@
+/* 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.
+ */
+
+&soc {
+	qcom,ion {
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
index 8314fab..3575c92 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -17,6 +17,7 @@
  */
 
 /include/ "msm8974-v2.0-1.dtsi"
+/include/ "apq8074-v2.0-1-ion.dtsi"
 
 &soc {
 	qcom,qseecom@a700000 {
@@ -55,3 +56,8 @@
 	status = "ok";
 };
 
+&ehci {
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
+
diff --git a/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi b/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
new file mode 100644
index 0000000..49d7ee1
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.2-ion.dtsi
@@ -0,0 +1,22 @@
+/* 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.
+ */
+
+&soc {
+	qcom,ion {
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x0dc00000 0x1e00000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.2.dtsi b/arch/arm/boot/dts/apq8074-v2.2.dtsi
index ddf7ec8..18f00c5 100644
--- a/arch/arm/boot/dts/apq8074-v2.2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.2.dtsi
@@ -17,6 +17,7 @@
  */
 
 /include/ "msm8974-v2.2.dtsi"
+/include/ "apq8074-v2.2-ion.dtsi"
 
 &soc {
 	qcom,qseecom@a700000 {
diff --git a/arch/arm/boot/dts/batterydata-mtp-3000mah.dtsi b/arch/arm/boot/dts/batterydata-mtp-3000mah.dtsi
new file mode 100644
index 0000000..8dc6f71
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-mtp-3000mah.dtsi
@@ -0,0 +1,108 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,mtp-3000mah {
+	qcom,fcc-mah = <3000>;
+	qcom,default-rbatt-mohm = <113>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,rbatt-capacitive-mohm = <50>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <200000>;
+	qcom,batt-id-kohm = <300>;
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <3030 3033 3037 3035 3031>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>,
+				<0>;
+		qcom,lut-data = <4191 4188 4183 4179 4174>,
+				<4106 4125 4127 4125 4121>,
+				<4046 4082 4082 4080 4077>,
+				<3966 4038 4044 4040 4035>,
+				<3922 3983 3994 3998 3997>,
+				<3886 3949 3966 3966 3962>,
+				<3856 3908 3937 3935 3931>,
+				<3832 3875 3908 3907 3903>,
+				<3814 3847 3874 3878 3875>,
+				<3799 3826 3831 3832 3830>,
+				<3787 3807 3811 3811 3809>,
+				<3775 3793 3795 3795 3793>,
+				<3764 3782 3783 3783 3781>,
+				<3752 3775 3773 3772 3769>,
+				<3739 3768 3766 3762 3755>,
+				<3725 3756 3756 3747 3733>,
+				<3710 3732 3734 3725 3711>,
+				<3696 3707 3705 3697 3684>,
+				<3681 3695 3686 3678 3667>,
+				<3667 3690 3684 3676 3665>,
+				<3658 3688 3683 3675 3664>,
+				<3646 3685 3681 3674 3663>,
+				<3631 3682 3679 3673 3660>,
+				<3612 3677 3676 3669 3655>,
+				<3589 3667 3666 3660 3639>,
+				<3560 3643 3636 3630 3599>,
+				<3523 3600 3586 3581 3546>,
+				<3474 3537 3518 3516 3477>,
+				<3394 3446 3425 3427 3379>,
+				<3257 3306 3273 3283 3213>,
+				<3000 3000 3000 3000 3000>;
+	};
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>;
+		qcom,lut-data = <1025 208 100 85 80>,
+				<1025 208 100 85 80>,
+				<1032 225 103 87 81>,
+				<959 249 107 91 82>,
+				<954 249 109 92 84>,
+				<953 255 117 94 84>,
+				<957 230 123 98 87>,
+				<968 216 134 102 91>,
+				<983 212 138 112 95>,
+				<1002 213 103 89 82>,
+				<1030 215 100 86 81>,
+				<1066 219 101 89 83>,
+				<1115 224 104 92 85>,
+				<1182 234 106 94 86>,
+				<1263 246 108 92 84>,
+				<1357 257 107 87 81>,
+				<1464 261 102 85 80>,
+				<1564 256 101 84 80>,
+				<1637 268 100 84 80>,
+				<1580 276 102 87 81>,
+				<1617 285 104 87 82>,
+				<1670 298 107 91 82>,
+				<1725 315 108 92 83>,
+				<1785 338 112 92 83>,
+				<1850 361 111 91 82>,
+				<1921 378 108 89 84>,
+				<2000 394 112 92 87>,
+				<2119 430 121 99 94>,
+				<2795 497 144 114 104>,
+				<8769 1035 672 322 234>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-palladium.dtsi b/arch/arm/boot/dts/batterydata-palladium.dtsi
new file mode 100644
index 0000000..95c4ff1
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-palladium.dtsi
@@ -0,0 +1,111 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,palladium-batterydata {
+	qcom,fcc-mah = <1500>;
+	qcom,default-rbatt-mohm = <210>;
+	qcom,rbatt-capacitive-mohm = <50>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <75>;
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <1467 1470 1473 1473 1470>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>,
+				<0>;
+		qcom,lut-data = <4175 4173 4167 4162 4157>,
+				<4097 4111 4112 4110 4107>,
+				<4039 4075 4072 4068 4064>,
+				<3963 4017 4025 4026 4025>,
+				<3920 3969 3984 3989 3988>,
+				<3887 3932 3957 3958 3955>,
+				<3856 3898 3929 3928 3925>,
+				<3830 3868 3900 3901 3898>,
+				<3808 3843 3858 3863 3862>,
+				<3793 3821 3827 3827 3827>,
+				<3779 3803 3807 3808 3807>,
+				<3768 3788 3792 3793 3792>,
+				<3757 3779 3780 3780 3779>,
+				<3746 3771 3772 3768 3768>,
+				<3734 3762 3765 3759 3749>,
+				<3722 3747 3753 3744 3730>,
+				<3707 3721 3731 3722 3709>,
+				<3693 3705 3704 3696 3683>,
+				<3678 3698 3687 3678 3667>,
+				<3664 3693 3683 3676 3665>,
+				<3656 3690 3682 3675 3664>,
+				<3646 3687 3681 3674 3662>,
+				<3634 3683 3680 3672 3661>,
+				<3618 3677 3676 3668 3656>,
+				<3599 3667 3667 3655 3639>,
+				<3573 3645 3638 3623 3603>,
+				<3541 3607 3591 3575 3554>,
+				<3496 3550 3528 3511 3490>,
+				<3428 3469 3445 3423 3400>,
+				<3312 3342 3308 3280 3250>,
+				<3000 3000 3000 3000 3000>;
+	};
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>,
+				<0>;
+		qcom,lut-data = <909 216 100 85 84>,
+				<859 238 106 88 86>,
+				<860 237 105 88 86>,
+				<808 239 107 90 88>,
+				<801 234 111 94 90>,
+				<801 230 118 97 92>,
+				<801 224 123 100 95>,
+				<807 221 128 106 99>,
+				<818 221 111 101 97>,
+				<841 225 101 88 87>,
+				<870 229 101 88 87>,
+				<906 235 103 91 90>,
+				<950 243 106 93 93>,
+				<998 253 110 93 96>,
+				<1051 263 113 94 90>,
+				<1116 272 113 91 88>,
+				<1200 275 111 91 88>,
+				<1312 298 108 90 87>,
+				<1430 329 104 88 87>,
+				<1484 351 107 91 89>,
+				<1446 345 110 93 90>,
+				<1398 344 112 94 90>,
+				<1466 358 115 96 91>,
+				<1490 357 117 96 90>,
+				<1589 365 117 94 89>,
+				<1828 379 111 91 88>,
+				<2151 399 111 93 91>,
+				<2621 436 117 98 95>,
+				<3404 496 130 106 100>,
+				<8212 616 150 1906 134>,
+				<135251 124940 59087 49820 29672>;
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
index 23091f0..2963d15 100644
--- a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
@@ -76,5 +76,6 @@
 		qcom,mdss-dsi-dma-trigger = <4>;
 		qcom,mdss-dsi-mdp-trigger = <0>;
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
index 9d244d8..23b65f3 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -26,13 +26,13 @@
 		qcom,mdss-dsi-stream = <0>;
 		qcom,mdss-dsi-panel-width = <480>;
 		qcom,mdss-dsi-panel-height = <800>;
-		qcom,mdss-dsi-h-front-porch = <70>;
-		qcom,mdss-dsi-h-back-porch = <100>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <94>;
 		qcom,mdss-dsi-h-pulse-width = <40>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
-		qcom,mdss-dsi-v-back-porch = <6>;
+		qcom,mdss-dsi-v-back-porch = <4>;
 		qcom,mdss-dsi-v-front-porch = <6>;
-		qcom,mdss-dsi-v-pulse-width = <4>;
+		qcom,mdss-dsi-v-pulse-width = <6>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
 		qcom,mdss-dsi-v-top-border = <0>;
@@ -42,62 +42,63 @@
 		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 79
-					39 01 00 00 00 00 03
-						BA 51 93
-					39 01 00 00 00 00 14
-						B1 00 50 44
-						EA 8D 08 11
-						11 11 27 2F
-						9A 1A 42 0B
-						6E F1 00 E6
-					39 01 00 00 00 00 0E
-						B2 00 00 3C
-						08 04 19 22
-						00 FF 08 04
-						19 20
-					39 01 00 00 00 00 20
-						B4 82 08 00
-						32 10 03 32
-						13 70 32 10
-						08 37 01 28
-						07 37 08 3C
-						08 44 44 08
-						00 40 08 28
-						08 30 30 04
-					39 01 00 00 00 00 30
-						D5 00 00 0A
-						00 01 05 00
-						03 00 88 88
-						88 88 23 01
-						67 45 02 13
-						88 88 88 88
-						88 88 88 88
-						88 88 54 76
-						10 32 31 20
-						88 88 88 88
-						88 88 00 00
-						00 00 00 00
-					39 01 00 00 00 00 24
-						E0 79 05 0F
-						14 26 29 3F
-						2B 44 04 0E
-						12 15 18 16
-						16 12 15 05
-						0F 14 26 29
-						3F 2B 44 04
-						0E 12 15 18
-						16 16 12 15
-					23 01 00 00 00 00 02
-						cc 02
-					39 01 00 00 00 00 05
-						B6 00 9C 00 9C
-					05 01 00 00 96 00 02
-						11 00
-					05 01 00 00 78 00 02
-						29 00
-					];
+			39 01 00 00 00 00 04
+				B9 FF 83 79
+			39 01 00 00 00 00 03
+				BA 51 93
+			39 01 00 00 00 00 14
+				B1 00 50 44
+				EA 8D 08 11
+				11 11 27 2F
+				9A 1A 42 0B
+				6E F1 00 E6
+			39 01 00 00 00 00 0E
+				B2 00 00 3C
+				08 04 19 22
+				00 FF 08 04
+				19 20
+			39 01 00 00 00 00 20
+				B4 80 08 00
+				32 10 03 32
+				13 70 32 10
+				08 37 01 28
+				07 37 08 35
+				08 3D 44 08
+				00 40 08 28
+				08 30 30 04
+			39 01 00 00 00 00 30
+				D5 00 00 0A
+				00 01 05 00
+				03 00 88 88
+				88 88 23 01
+				67 45 02 13
+				88 88 88 88
+				88 88 88 88
+				88 88 54 76
+				10 32 31 20
+				88 88 88 88
+				88 88 00 00
+				00 00 00 00
+			39 01 00 00 00 00 24
+				E0 79 05 0F
+				14 26 20 3F
+				2A 43 04 0C
+				11 15 17 15
+				15 10 13 05
+				0F 14 26 20
+				3F 2A 43 04
+				0C 11 15 17
+				15 15 10 13
+			23 01 00 00 00 00 02
+				cc 02
+			39 01 00 00 00 00 05
+				B6 00 9C 00
+				9C
+			05 01 00 00 96 00 02
+				11 00
+			05 01 00 00 78 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";
@@ -109,7 +110,7 @@
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
-		qcom,mdss-dsi-panel-timings = [75 1A 11 00 3D 45 15 1D 1C 03 04 00];
+		qcom,mdss-dsi-panel-timings = [78 1B 11 00 3E 43 16 1E 1D 03 04 00];
 		qcom,mdss-dsi-t-clk-post = <0x04>;
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
@@ -117,6 +118,7 @@
 		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-hx8394a-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
index c9d887b..83351ca 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -78,6 +78,7 @@
 		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 1>, <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/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
index 829197a..9bb11da 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -268,6 +268,7 @@
 		qcom,mdss-dsi-dma-trigger = <4>;
 		qcom,mdss-dsi-mdp-trigger = <0>;
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
 
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index 0918cf4..a24cb58 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -531,6 +531,9 @@
 		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 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <59>;
+		qcom,mdss-pan-physical-height-dimension = <104>;
 
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 6d68a3e..79618b9 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -527,6 +527,9 @@
 		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 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <59>;
+		qcom,mdss-pan-physical-height-dimension = <104>;
 
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
index 49aef24..2312b37 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
@@ -582,6 +582,7 @@
 		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 1>, <1 20>;
 
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
index 89a5063..9477c56 100644
--- a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -261,6 +261,7 @@
 		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-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index c627e7a..285d8fc 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -67,6 +67,7 @@
 		qcom,mdss-dsi-dma-trigger = <4>;
 		qcom,mdss-dsi-mdp-trigger = <4>;
 		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/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index ccbb659..501fdde 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -39,5 +39,6 @@
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
 		qcom,panel-off-cmds = [22 01 00 00 00 00 02 00 00];
 		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index 7bb414a..bb8389f 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -115,5 +115,6 @@
 		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 1>, <1 20>;
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 0b98db7..f7de416 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -90,6 +90,8 @@
 		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-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
index f6e6df8..d170833 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -166,5 +166,6 @@
 		qcom,mdss-dsi-dma-trigger = <4>;
 		qcom,mdss-dsi-mdp-trigger = <2>;
 		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-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
index fae4834..546a90f 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
@@ -164,5 +164,6 @@
 		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/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 8ab9985..8891935 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -33,6 +33,7 @@
 		qcom,msm-bus,vectors-KBps =
 				<11 512 0 0>,
 				<11 512 0 1000>;
+		qcom,msm-enable-remote-spinlock;
 		status = "disabled";
 
 		lpass_q6_fw: qcom,iommu-ctx@fd000000 {
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1820dc7..8523524 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -113,7 +113,7 @@
 							"vdd-loop";
 			};
 
-			qcom,bat-if@1200 {
+			pm8110_chg_batif: qcom,bat-if@1200 {
 				status = "disabled";
 				reg = <0x1200 0x100>;
 				interrupts =	<0x0 0x12 0x0>,
@@ -315,7 +315,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 5642d4d..5e0abea 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -131,7 +131,7 @@
 							"vdd-loop";
 			};
 
-			qcom,bat-if@1200 {
+			pm8226_chg_batif: qcom,bat-if@1200 {
 				status = "disabled";
 				reg = <0x1200 0x100>;
 				interrupts =	<0x0 0x12 0x0>,
@@ -189,7 +189,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -831,10 +831,10 @@
 			pm8226_flash0: qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				label = "flash";
 				linux,default-trigger =
@@ -847,10 +847,10 @@
 			pm8226_flash1: qcom,flash_1 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				linux,default-trigger =
 						"flash1_trigger";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 583cd3c..8a239cc 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -120,7 +120,7 @@
 		qcom,v-cutoff-uv = <3400000>;
 		qcom,max-voltage-uv = <4200000>;
 		qcom,r-conn-mohm = <0>;
-		qcom,shutdown-soc-valid-limit = <20>;
+		qcom,shutdown-soc-valid-limit = <100>;
 		qcom,adjust-soc-low-threshold = <15>;
 		qcom,ocv-voltage-high-threshold-uv = <3750000>;
 		qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -250,7 +250,7 @@
 						"vdd-loop";
 		};
 
-		qcom,bat-if@1200 {
+		pm8941_chg_batif: qcom,bat-if@1200 {
 			status = "disabled";
 			reg = <0x1200 0x100>;
 			interrupts =	<0x0 0x12 0x0>,
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 3eacef2..fd6d618 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -402,7 +402,7 @@
 	};
 
 	qcom,camera@6a {
-		compatible = "qcom,ov5648";
+		compatible = "ovti,ov5648";
 		reg = <0x6a>;
 		qcom,slave-id = <0x6c 0x300a 0x5648>;
 		qcom,csiphy-sd-index = <1>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 066d6c2..3ebe225 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -29,6 +29,8 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
@@ -102,7 +104,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
+		qcom,headset-jack-type-NC;
 	};
 
 	sound-9302 {
@@ -120,7 +122,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
+		qcom,headset-jack-type-NC;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 2ec7b6c..3e2507ff 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -37,6 +37,7 @@
 		qcom,mdss-intf-off = <0x00000000 0x00021300>;
 		qcom,mdss-rot-block-size = <64>;
 		qcom,mdss-smp-mb-per-pipe = <2>;
+		vdd-cx-supply = <&pm8226_s1_corner>;
 
 		qcom,vbif-settings = <0x004 0x00000001>,
 				     <0x0D8 0x00000707>,
@@ -49,6 +50,7 @@
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
 			qcom,memory-reservation-size = <0x800000>;
+			qcom,memblock-reserve = <0x03200000 0xFA0000>;
 		};
 
 		mdss_fb1: qcom,mdss_fb_wfd {
@@ -77,7 +79,6 @@
 			00 00 00 00 0a 00 00 01 97
 			00 00 00 00 0f 00 00 01 97
 			00 c0 00 00 00 00 00 01 bb];
-		qcom,platform-reset-sequence = <1 20 0 1 1 20>;
 		qcom,platform-supply-entry1 {
 			qcom,supply-name = "vdd";
 			qcom,supply-min-voltage = <2800000>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index f4f7442..dbd2031 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -29,6 +29,8 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
@@ -38,6 +40,8 @@
 			reg = <0x0e>;
 			qcom,irq-gpio = <&msmgpio 21 0x00>;
 			qcom,dis-gpio = <&msmgpio 20 0x00>;
+			qcom,clk-src = "BBCLK2";
+			qcom,clk-en-gpio = <&msmgpio 0 0x00>;
 			interrupt-parent = <&msmgpio>;
 			interrupts = <21 0>;
 			qcom,clk-gpio = <&pm8226_gpios 3 0>;
@@ -460,6 +464,16 @@
 	};
 };
 
+/ {
+	mtp_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-palladium.dtsi"
+		/include/ "batterydata-mtp-3000mah.dtsi"
+	};
+};
+
 &pm8226_bms {
 	status = "ok";
 	qcom,enable-fcc-learning;
@@ -467,10 +481,12 @@
 	qcom,min-fcc-ocv-pc = <30>;
 	qcom,min-fcc-learning-samples = <5>;
 	qcom,fcc-resolution = <10>;
+	qcom,battery-data = <&mtp_batterydata>;
 };
 
 &pm8226_chg {
 	qcom,charging-disabled;
+	qcom,battery-data = <&mtp_batterydata>;
 };
 
 &slim_msm {
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
new file mode 100755
index 0000000..66f5095
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -0,0 +1,215 @@
+/* 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/ "msm8226-qrd.dtsi"
+
+&soc {
+	sound {
+		qcom,model = "msm8226-tapan-skuf-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"Lineout_1 amp", "LINEOUT1",
+			"Lineout_2 amp", "LINEOUT2",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-vdd-spkr-gpios;
+		qcom,cdc-us-euro-gpios;
+	};
+
+    sound-9302 {
+          qcom,model = "msm8226-tapan9302-skuf-snd-card";
+
+          qcom,audio-routing =
+              "RX_BIAS", "MCLK",
+              "LDO_H", "MCLK",
+              "SPK_OUT", "MCLK",
+              "SPK_OUT", "EXT_VDD_SPKR",
+              "Lineout_1 amp", "LINEOUT1",
+              "Lineout_2 amp", "LINEOUT2",
+              "AMIC1", "MIC BIAS1 External",
+              "MIC BIAS1 External", "Handset Mic",
+              "AMIC2", "MIC BIAS2 External",
+              "MIC BIAS2 External", "Headset Mic",
+              "AMIC3", "MIC BIAS1 External",
+              "MIC BIAS1 External", "Handset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-vdd-spkr-gpios;
+		qcom,cdc-us-euro-gpios;
+	};
+
+	tp_power: regulator-tp {
+		compatible = "regulator-fixed";
+		regulator-name = "tp_power";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		gpio = <&msmgpio 15 0>;
+		startup-delay-us = <20000>;
+		enable-active-high;
+	};
+
+	i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,product-id = "915";
+			goodix,cfg-data0 = [
+				41 D0 02 00 05 05 35 01 01 0F
+				2D 06 50 32 03 05 00 00 00 00
+				00 00 05 18 1A 1E 14 8C 0E 0E
+				3F 3D 2A 09 00 00 00 99 04 1D
+				00 00 00 00 00 00 00 00 00 00
+				00 32 6E 94 D5 01 05 00 00 04
+				CE 36 00 B5 3F 00 9E 4A 00 8B
+				57 00 7C 65 00 7C 10 38 68 00
+				56 50 35 66 66 27 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 02 04 06 08 0A 0C 0E 10
+				12 14 16 18 1A 1C 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 00 02 04 06 08 0A 0C 0F
+				10 12 13 14 16 18 1C 1D 1E 1F
+				20 21 22 24 26 28 29 2A 00 00
+				00 FF FF FF FF FF FF FF FF FF
+				FF FF FF FF A3 01];
+			goodix,cfg-data1 = [
+				41 D0 02 00 05 05 35 01 01 C3
+				2D 06 55 32 03 03 00 00 00 00
+				00 00 05 0A 0C 0F 0A 8C 0E 0E
+				30 2E B8 08 00 00 00 8F 03 1D
+				00 00 00 00 00 00 00 00 00 00
+				00 2D 62 94 D5 02 05 00 00 04
+				96 30 00 80 39 00 71 42 00 63
+				4D 00 56 5A 00 56 10 38 68 00
+				56 50 35 AA AA 27 00 00 00 00
+				00 01 1B 14 0C 14 00 00 01 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 02 04 06 08 0A 0C 0E 10
+				12 14 16 18 1A 1C FF FF FF FF
+				FF FF FF FF FF FF FF FF FF FF
+				FF FF 00 02 04 06 08 0A 0C 0F
+				10 12 13 14 16 18 1C 1D 1E 1F
+				20 21 22 24 26 28 29 2A FF FF
+				FF FF FF FF FF FF FF FF FF FF
+				FF FF FF FF 3E 01];
+		};
+	};
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a300 {
+			status = "disabled";
+		};
+
+		qcom,leds@a500 {
+			status = "disabled";
+		};
+	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "disabled";
+		};
+	};
+};
+
+&pm8226_mpps {
+	mpp@a300 { /* MPP 4 */
+		/* camera2_id */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <3>; /* AMUX 8 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* camera_id */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <1>; /* AMUX 6 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+
+};
+
+&pm8226_vadc {
+	chan@13 {
+		label = "camera2_id";
+		reg = <0x13>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@15 {
+		label = "camera_id";
+		reg = <0x15>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_nt35521_720_vid>;
+};
+
+&dsi_nt35521_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 53e0578..701a3ef 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -29,7 +29,10 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
+
 		focaltech@38 {
 			compatible = "focaltech,5x06";
 			reg = <0x38>;
@@ -382,6 +385,7 @@
 	status = "okay";
 	qcom,battery-data = <&qrd_batterydata>;
 	qcom,tchg-mins = <240>;
+	qcom,ovp-monitor-en;
 };
 
 &pm8226_gpios {
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 415912f..23a2158 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -41,8 +41,13 @@
 		qcom,pvs-fuse = <22 6 5>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1260000 1245000 1230000 1215000
+					1200000 1185000 1170000 1155000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1275000 1275000
+					1275000 1275000>;
 		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
 		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
@@ -486,6 +491,10 @@
 	otg-parent-supply = <&pm8226_chg_boost>;
 };
 
+&pm8226_chg_batif {
+	regulator-name = "batfet";
+};
+
 &pm8226_chg_otg {
 	regulator-name = "8226_smbbp_otg";
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index dcf46e6..02feec8 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -99,6 +99,9 @@
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+				11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
 		qcom,L2-spm-is-apcs-master;
 	};
 
@@ -113,8 +116,8 @@
 			qcom,mode = "wfi";
 			qcom,l2 = "l2_cache_active";
 			qcom,latency-us = <1>;
-			qcom,ss-power = <784>;
-			qcom,energy-overhead = <190000>;
+			qcom,ss-power = <530>;
+			qcom,energy-overhead = <52800>;
 			qcom,time-overhead = <100>;
 		};
 
@@ -122,30 +125,30 @@
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
 			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <3000>;
-			qcom,ss-power = <725>;
-			qcom,energy-overhead = <99500>;
-			qcom,time-overhead = <3130>;
+			qcom,latency-us = <500>;
+			qcom,ss-power = <410>;
+			qcom,energy-overhead = <603400>;
+			qcom,time-overhead = <1200>;
 		};
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <138>;
-			qcom,energy-overhead = <1208400>;
-			qcom,time-overhead = <9200>;
+			qcom,l2 = "l2_cache_pc_no_rpm";
+			qcom,latency-us = <1000>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
 		};
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <30000>;
-			qcom,ss-power = <110>;
-			qcom,energy-overhead = <1250300>;
-			qcom,time-overhead = <9500>;
+			qcom,latency-us = <11000>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
 		};
 	};
 
@@ -266,6 +269,7 @@
 			<38  108>,
 			<39  109>,
 			<40  110>,
+			<41  115>,
 			<54  111>,
 			<55  113>;
 	};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8974pro-ab-fluid.dts
copy to arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts
index 9a31834..43e1e21 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts
@@ -11,18 +11,12 @@
  */
 
 /dts-v1/;
-
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-fluid.dtsi"
+/include/ "msm8226-v1.dtsi"
+/include/ "msm8226-qrd-skuf.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro FLUID";
-	compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
-	qcom,msm-id = <209 3 0x10000>,
-		      <211 3 0x10000>,
-		      <212 3 0x10000>,
-		      <214 3 0x10000>,
-		      <215 3 0x10000>,
-		      <217 3 0x10000>,
-		      <218 3 0x10000>;
+	model = "Qualcomm MSM 8226v1 QRD PVT";
+	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,skuf", "qcom,qrd";
+	qcom,board-id = <0x2000b 2>;
 };
+
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index cbafe80..b836928 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
-/include/ "msm8226-qrd.dtsi"
+/include/ "msm8226-qrd-skuf.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v1 QRD";
@@ -20,161 +20,10 @@
 	qcom,board-id = <11 2>;
 };
 
-&soc {
-	sound {
-		qcom,model = "msm8226-tapan-skuf-snd-card";
-
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"SPK_OUT", "MCLK",
-			"SPK_OUT", "EXT_VDD_SPKR",
-			"Lineout_1 amp", "LINEOUT1",
-			"Lineout_2 amp", "LINEOUT2",
-			"AMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic";
-
-		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
-		qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,cdc-vdd-spkr-gpios;
-		qcom,cdc-us-euro-gpios;
-	};
-
-	tp_power: regulator-tp {
-		compatible = "regulator-fixed";
-		regulator-name = "tp_power";
-		regulator-min-microvolt = <2800000>;
-		regulator-max-microvolt = <2800000>;
-		gpio = <&msmgpio 15 0>;
-		startup-delay-us = <20000>;
-		enable-active-high;
-	};
-
-	i2c@f9927000 {
-		goodix@5d {
-			compatible = "goodix,gt9xx";
-			reg = <0x5d>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2008>;
-			reset-gpios = <&msmgpio 16 0x00>;
-			interrupt-gpios = <&msmgpio 17 0x00>;
-			avdd-supply = <&tp_power>;
-			goodix,panel-coords = <0 0 720 1200>;
-			goodix,display-coords = <0 0 720 1080>;
-			goodix,button-map= <158 102 139>;
-			goodix,family-id = <0x0>;
-			goodix,cfg-data = [
-			41 D0 02 00 05 0A 35 01 01 0F
-			2D 08 55 32 03 04 00 00 00 00
-			00 00 05 0A 0C 0F 0A 8C 0E 0E
-			30 2E B8 08 00 00 00 83 03 1D
-			00 00 00 00 00 00 00 00 00 00
-			00 2D 62 94 C5 02 05 00 00 04
-			96 30 00 80 39 00 71 42 00 63
-			4D 00 56 5A 00 56 10 38 68 00
-			56 50 35 AA AA 27 00 00 00 00
-			00 01 1B 14 0C 14 00 00 01 00
-			00 00 00 00 00 00 00 00 00 00
-			00 00 02 04 06 08 0A 0C 0E 10
-			12 14 16 18 1A 1C FF FF FF FF
-			FF FF FF FF FF FF FF FF FF FF
-			FF FF 00 02 04 06 08 0A 0C 0F
-			10 12 13 14 16 18 1C 1D 1E 1F
-			20 21 22 24 26 28 29 2A FF FF
-			FF FF FF FF FF FF FF FF FF FF
-			FF FF FF FF 06 01];
-		};
-	};
-};
-
-&spmi_bus {
-	qcom,pm8226@0 {
-		qcom,leds@a300 {
-			status = "disabled";
-		};
-
-		qcom,leds@a500 {
-			status = "disabled";
-		};
-	};
-
-	qcom,pm8226@1 {
-		qcom,leds@d800 {
-			status = "disabled";
-		};
-	};
-};
-
-&pm8226_mpps {
-	mpp@a300 { /* MPP 4 */
-		/* camera2_id */
-		qcom,mode = <4>; /* AIN input */
-		qcom,invert = <1>; /* Enable MPP */
-		qcom,ain-route = <3>; /* AMUX 8 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* camera_id */
-		qcom,mode = <4>; /* AIN input */
-		qcom,invert = <1>; /* Enable MPP */
-		qcom,ain-route = <1>; /* AMUX 6 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-	};
-
-};
-
-&pm8226_vadc {
-	chan@13 {
-		label = "camera2_id";
-		reg = <0x13>;
-		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@15 {
-		label = "camera_id";
-		reg = <0x15>;
-		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-};
-
-&qrd_batterydata {
-	qcom,rpull-up-kohm = <100>;
-	qcom,vref-batt-therm = <1800000>;
-
-	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
-};
-
 &pm8226_bms {
-	qcom,battery-data = <&qrd_batterydata>;
+        qcom,use-external-rsense;
 };
 
-&pm8226_chg {
-	qcom,battery-data = <&qrd_batterydata>;
-};
-
-&mdss_dsi0 {
-	qcom,dsi-pref-prim-pan = <&dsi_nt35521_720_vid>;
-};
-
-&dsi_nt35521_720_vid {
-	qcom,cont-splash-enabled;
+&pm8226_iadc {
+        qcom,rsense = <10000000>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-cdp.dts
index 3d40180..3302d26 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-cdp.dts
@@ -20,3 +20,7 @@
 	compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
 	qcom,board-id = <1 0>;
 };
+
+&hsic_host {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index 9ee47e2..31d5a8f 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -98,6 +98,9 @@
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
 		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
 				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+				11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
@@ -115,8 +118,8 @@
 			qcom,mode = "wfi";
 			qcom,l2 = "l2_cache_active";
 			qcom,latency-us = <1>;
-			qcom,ss-power = <784>;
-			qcom,energy-overhead = <190000>;
+			qcom,ss-power = <530>;
+			qcom,energy-overhead = <52800>;
 			qcom,time-overhead = <100>;
 		};
 
@@ -124,30 +127,40 @@
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
 			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <3000>;
-			qcom,ss-power = <725>;
-			qcom,energy-overhead = <99500>;
-			qcom,time-overhead = <3130>;
+			qcom,latency-us = <500>;
+			qcom,ss-power = <410>;
+			qcom,energy-overhead = <603400>;
+			qcom,time-overhead = <1200>;
 		};
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <138>;
-			qcom,energy-overhead = <1208400>;
-			qcom,time-overhead = <9200>;
+			qcom,latency-us = <10700>;
+			qcom,ss-power = <372>;
+			qcom,energy-overhead = <738750>;
+			qcom,time-overhead = <1410>;
 		};
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
+			qcom,l2 = "l2_cache_pc_no_rpm";
+			qcom,latency-us = <1000>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <30000>;
-			qcom,ss-power = <110>;
-			qcom,energy-overhead = <1250300>;
-			qcom,time-overhead = <9500>;
+			qcom,latency-us = <11000>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
 		};
 	};
 
@@ -268,6 +281,7 @@
 			<38  108>,
 			<39  109>,
 			<40  110>,
+			<41  115>,
 			<54  111>,
 			<55  113>;
 	};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8974pro-ab-fluid.dts
copy to arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts
index 9a31834..f5ac301 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts
@@ -11,18 +11,12 @@
  */
 
 /dts-v1/;
-
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-fluid.dtsi"
+/include/ "msm8226-v2.dtsi"
+/include/ "msm8226-qrd-skuf.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro FLUID";
-	compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
-	qcom,msm-id = <209 3 0x10000>,
-		      <211 3 0x10000>,
-		      <212 3 0x10000>,
-		      <214 3 0x10000>,
-		      <215 3 0x10000>,
-		      <217 3 0x10000>,
-		      <218 3 0x10000>;
+	model = "Qualcomm MSM 8226v2 QRD PVT";
+	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,skuf", "qcom,qrd";
+	qcom,board-id = <0x2000b 0x2>;
 };
+
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index 77037be..9aa12f6 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -12,7 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
-/include/ "msm8226-qrd.dtsi"
+/include/ "msm8226-qrd-skuf.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
@@ -20,166 +20,10 @@
 	qcom,board-id = <0xb 0x2>;
 };
 
-&soc {
-	sound {
-		qcom,model = "msm8226-tapan-skuf-snd-card";
-
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"SPK_OUT", "MCLK",
-			"SPK_OUT", "EXT_VDD_SPKR",
-			"Lineout_1 amp", "LINEOUT1",
-			"Lineout_2 amp", "LINEOUT2",
-			"AMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic";
-
-		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
-		qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,cdc-vdd-spkr-gpios;
-		qcom,cdc-us-euro-gpios;
-	};
-
-	tp_power: regulator-tp {
-		compatible = "regulator-fixed";
-		regulator-name = "tp_power";
-		regulator-min-microvolt = <2800000>;
-		regulator-max-microvolt = <2800000>;
-		gpio = <&msmgpio 15 0>;
-		startup-delay-us = <20000>;
-		enable-active-high;
-	};
-
-	i2c@f9927000 {
-		goodix@5d {
-			compatible = "goodix,gt9xx";
-			reg = <0x5d>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2008>;
-			reset-gpios = <&msmgpio 16 0x00>;
-			interrupt-gpios = <&msmgpio 17 0x00>;
-			avdd-supply = <&tp_power>;
-			goodix,panel-coords = <0 0 720 1200>;
-			goodix,display-coords = <0 0 720 1080>;
-			goodix,button-map= <158 102 139>;
-			goodix,family-id = <0x0>;
-			goodix,cfg-data = [
-			41 D0 02 00 05 0A 35 01 01 0F
-			2D 08 55 32 03 04 00 00 00 00
-			00 00 05 0A 0C 0F 0A 8C 0E 0E
-			30 2E B8 08 00 00 00 83 03 1D
-			00 00 00 00 00 00 00 00 00 00
-			00 2D 62 94 C5 02 05 00 00 04
-			96 30 00 80 39 00 71 42 00 63
-			4D 00 56 5A 00 56 10 38 68 00
-			56 50 35 AA AA 27 00 00 00 00
-			00 01 1B 14 0C 14 00 00 01 00
-			00 00 00 00 00 00 00 00 00 00
-			00 00 02 04 06 08 0A 0C 0E 10
-			12 14 16 18 1A 1C FF FF FF FF
-			FF FF FF FF FF FF FF FF FF FF
-			FF FF 00 02 04 06 08 0A 0C 0F
-			10 12 13 14 16 18 1C 1D 1E 1F
-			20 21 22 24 26 28 29 2A FF FF
-			FF FF FF FF FF FF FF FF FF FF
-			FF FF FF FF 06 01];
-		};
-	};
-};
-
-&spmi_bus {
-	qcom,pm8226@0 {
-		qcom,leds@a300 {
-			status = "disabled";
-		};
-
-		qcom,leds@a500 {
-			status = "disabled";
-		};
-	};
-
-	qcom,pm8226@1 {
-		qcom,leds@d800 {
-			status = "disabled";
-		};
-	};
-};
-
-&pm8226_mpps {
-	mpp@a300 { /* MPP 4 */
-		/* camera2_id */
-		qcom,mode = <4>; /* AIN input */
-		qcom,invert = <1>; /* Enable MPP */
-		qcom,ain-route = <3>; /* AMUX 8 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* camera_id */
-		qcom,mode = <4>; /* AIN input */
-		qcom,invert = <1>; /* Enable MPP */
-		qcom,ain-route = <1>; /* AMUX 6 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-	};
-
-};
-
-&pm8226_vadc {
-	chan@13 {
-		label = "camera2_id";
-		reg = <0x13>;
-		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@15 {
-		label = "camera_id";
-		reg = <0x15>;
-		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-};
-
-&qrd_batterydata {
-	qcom,rpull-up-kohm = <100>;
-	qcom,vref-batt-therm = <1800000>;
-
-	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
-};
-
 &pm8226_bms {
 	qcom,use-external-rsense;
-	qcom,battery-data = <&qrd_batterydata>;
-};
-
-&pm8226_chg {
-	qcom,battery-data = <&qrd_batterydata>;
 };
 
 &pm8226_iadc {
 	qcom,rsense = <10000000>;
 };
-
-&mdss_dsi0 {
-	qcom,dsi-pref-prim-pan = <&dsi_nt35521_720_vid>;
-};
-
-&dsi_nt35521_720_vid {
-	qcom,cont-splash-enabled;
-};
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 8f22ceb..a57adcd 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -33,27 +33,32 @@
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1330000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
+	qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
 	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 22d6948..8958984 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -33,7 +33,7 @@
 
 		adsp_mem: adsp_region {
 			linux,contiguous-region;
-			reg = <0 0xc00000>;
+			reg = <0 0x2a00000>;
 			label = "adsp_mem";
 		};
 
@@ -201,6 +201,12 @@
 		};
 	};
 
+	qcom,vidc {
+		compatible = "qcom,msm-vidc";
+		qcom,hfi = "q6";
+		qcom,max-hw-load = <108000>; /* 720p @ 30 * 1  */
+	};
+
 	qcom,wfd {
 		compatible = "qcom,msm-wfd";
 	};
@@ -293,6 +299,37 @@
 		qcom,android-usb-swfi-latency = <1>;
 	};
 
+	hsic_host: hsic@f9a00000 {
+		status = "disabled";
+		compatible = "qcom,hsic-host";
+		reg = <0xf9a00000 0x400>;
+		#address-cells = <0>;
+		interrupt-parent = <&hsic_host>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 136 0
+			1 &intc 0 148 0
+			2 &msmgpio 115 0x8>;
+		interrupt-names = "core_irq", "async_irq", "wakeup";
+		hsic_vdd_dig-supply = <&pm8226_s1_corner>;
+		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+		hsic,strobe-gpio = <&msmgpio 115 0x00>;
+		hsic,data-gpio = <&msmgpio 116 0x00>;
+		hsic,ignore-cal-pad-config;
+		hsic,strobe-pad-offset = <0x2050>;
+		hsic,data-pad-offset = <0x2054>;
+		qcom,phy-susp-sof-workaround;
+		hsic,vdd-voltage-level = <1 5 7>;
+
+		qcom,msm-bus,name = "hsic";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<85 512 0 0>,
+				<85 512 40000 160000>;
+	};
+
 	wcd9xxx_intc: wcd9xxx-irq {
 		compatible = "qcom,wcd9xxx-irq";
 		interrupt-controller;
@@ -585,6 +622,7 @@
 		gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
 		qcom,has-pronto-hw;
 		qcom,has-autodetect-xo;
+		qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
 	};
 
 	qcom,msm-adsp-sensors {
@@ -1081,6 +1119,10 @@
 		qcom,core-limit-temp = <80>;
 		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <0xe>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor5",
+				"tsens_tz_sensor2", "tsens_tz_sensor2";
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
 		vdd-dig-supply = <&pm8226_s1_floor_corner>;
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 6b72e66..c6e81d8 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -56,8 +56,8 @@
 			qcom,ws = <10000>;
 			qcom,qport = <2>;
 			qcom,mas-hw-id = <11>;
-			qcom,prio1 = <2>;
-			qcom,prio0 = <2>;
+			qcom,prio1 = <3>;
+			qcom,prio0 = <3>;
 		};
 
 		mas-mdpe {
@@ -71,8 +71,8 @@
 			qcom,ws = <10000>;
 			qcom,qport = <7>;
 			qcom,mas-hw-id = <11>;
-			qcom,prio1 = <2>;
-			qcom,prio0 = <2>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
 		};
 
 		fab-bimc {
@@ -913,7 +913,7 @@
 		qcom,fabclk-dual = "mem_clk";
 		qcom,fabclk-active = "mem_a_clk";
 		qcom,ntieredslaves = <0>;
-		qcom,qos-freq = <4800>;
+		qcom,qos-freq = <19200>;
 		qcom,hw-sel = "BIMC";
 		qcom,rpm-en;
 
@@ -930,13 +930,19 @@
 			qcom,masterp = <0>;
 			qcom,tier = <2>;
 			qcom,hw-sel = "BIMC";
-			qcom,mode = "Fixed";
+			qcom,mode = "Limiter";
 			qcom,qport = <0>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <0>;
 			qcom,prio-rd = <0>;
 			qcom,prio-wr = <0>;
 			qcom,prio-lvl = <0>;
+			qcom,mode-thresh = "Fixed";
+			qcom,thresh = <800000>;
+			qcom,dual-conf;
+			qcom,bimc,bw = <300000>;
+			qcom,bimc,gp = <5>;
+			qcom,bimc,thmp = <50>;
 		};
 
 		mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
index e133117..bdcab77 100644
--- a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -149,6 +149,44 @@
 		qcom,cci-master = <0>;
 	};
 
+	qcom,camera@34 {
+		compatible = "sne,imx134";
+		reg = <0x34>;
+		qcom,slave-id = <0x34 0x0016 0x0134>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx134";
+		cam_vdig-supply = <&pm8110_l2>;
+		cam_vana-supply = <&pm8110_l19>;
+		cam_vio-supply = <&pm8110_l14>;
+		cam_vaf-supply = <&pm8110_l16>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							 "cam_vaf";
+		qcom,cam-vreg-type = <0 0 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 1800000 2850000 3000000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000 2850000 3000000>;
+		qcom,cam-vreg-op-mode = <200000 8000 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 13 0>,
+			<&msmgpio 21 0>,
+			<&msmgpio 20 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,csi-lane-assign = <0xe4>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+
 	qcom,camera@6d {
 		compatible = "qcom,ov9724";
 		reg = <0x6d>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index f0d1715..452cc2f 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -172,6 +172,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index f37a42b..929659e 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -20,6 +20,7 @@
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
+			qcom,memblock-reserve = <0x3200000 0x800000>;
 		};
 	};
 
@@ -37,9 +38,6 @@
 		qcom,platform-reset-gpio = <&msmgpio 41 0>;
 		qcom,platform-te-gpio = <&msmgpio 12 0>;
 		qcom,platform-mode-gpio = <&msmgpio 7 0>;
-
-		qcom,platform-reset-sequence = <1 20 0 2 1 20 2>;
-
 		qcom,platform-strength-ctrl = [ff 06];
 		qcom,platform-bist-ctrl = [03 03 00 00 0f 00];
 		qcom,platform-regulator-settings = [02 08 05 00 20 03];
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 56ef7ca..8d0e201 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -131,6 +131,17 @@
 			capella,ps_conf1_val = <0x0006>;
 			capella,ps_conf3_val = <0x3010>;
 		};
+		nfc-nci@0e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 77 0x00>;
+			qcom,dis-gpio = <&msmgpio 93 0x00>;
+			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
+			qcom,clk-src = "GPCLK";
+			interrupt-parent = <&msmgpio>;
+			interrupts = <77 0>;
+			qcom,clk-gpio = <&pm8110_gpios 1 0>;
+		};
 	};
 
 	gen-vkeys {
@@ -228,6 +239,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
@@ -373,6 +385,11 @@
 
 &pm8110_gpios {
 	gpio@c000 { /* GPIO 1 */
+		qcom,mode = <0>;		/* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c100 { /* GPIO 2 */
@@ -407,8 +424,23 @@
 	};
 };
 
+/ {
+	mtp_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-palladium.dtsi"
+		/include/ "batterydata-mtp-3000mah.dtsi"
+	};
+};
+
 &pm8110_bms {
 	status = "ok";
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pm8110_chg {
+	qcom,battery-data = <&mtp_batterydata>;
 };
 
 &mdss_mdp {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 17bf329..2fe6a34 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -44,6 +44,40 @@
 			focaltech,no-force-update;
 			focaltech,i2c-pull-up;
 		};
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2008>;
+			reset-gpios = <&msmgpio 0 0x00>;
+			interrupt-gpios = <&msmgpio 1 0x00>;
+			vdd-supply = <&pm8110_l19>;
+			vcc-i2c-supply = <&pm8110_l14>;
+			goodix,panel-coords = <0 0 540 980>;
+			goodix,display-coords = <0 0 540 960>;
+			goodix,button-map= <139 102 158>;
+			goodix,product-id = "915";
+			goodix,cfg-data0 = [
+				46 1C 02 C0 03 0A 05 11 01 08
+				14 3B 46 32 03 05 00 00 00 00
+				00 00 00 00 00 00 00 8A 09 0B
+				39 00 99 0A 00 00 02 83 03 1D
+				00 08 00 00 00 00 00 00 00 00
+				00 1D 73 94 C5 02 07 00 00 04
+				78 21 00 5C 2C 00 48 3A 00 3A
+				4C 00 2F 65 00 30 10 30 50 00
+				56 45 35 FF FF 17 00 00 00 00
+				00 01 1C 15 0C 14 5F 03 02 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 16 14 12 10 0E 0C 0A 08
+				06 04 02 FF FF FF 00 00 00 00
+				00 00 00 00 00 00 00 00 00 00
+				00 00 22 21 20 1F 1E 1D 1C 18
+				16 12 10 0F 0C 0A 08 06 04 02
+				00 FF FF FF FF FF FF FF 00 00
+				00 FF FF FF FF FF FF FF FF FF
+				F8 FF FF FF E4 01];
+		};
 	};
 	gen-vkeys {
 		compatible = "qcom,gen-vkeys";
@@ -55,6 +89,7 @@
 		qcom,key-codes = <139 102 158>;
 		qcom,y-offset = <0>;
 	};
+
     i2c@f9925000 {
 		fsl@1c {
 			compatible = "fsl,mma8x5x";
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index 3fb33e9..83d84c0 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -135,13 +135,14 @@
 	};
 
     sound {
-        qcom,audio-routing =
-            "RX_BIAS", "MCLK",
-            "INT_LDO_H", "MCLK",
-            "MIC BIAS Internal1", "Handset Mic",
-            "MIC BIAS Internal2", "Headset Mic",
-            "AMIC1", "MIC BIAS Internal1",
-            "AMIC2", "MIC BIAS Internal2";
+	qcom,audio-routing =
+		"RX_BIAS", "MCLK",
+		"INT_LDO_H", "MCLK",
+		"MIC BIAS Internal1", "Handset Mic",
+		"MIC BIAS Internal2", "Headset Mic",
+		"AMIC1", "MIC BIAS Internal1",
+		"AMIC2", "MIC BIAS Internal2";
+	qcom,mbhc-bias-internal;
     };
 };
 
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 1929b50..f97d991 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -42,10 +42,15 @@
 		qcom,pvs-fuse = <23 6 5>;
 		qcom,pvs-fuse-redun = <61 47 5>;
 
-		qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
-					1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
-		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000>;
+		qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+		qcom,pvs-corner-ceiling-nom  = <1075000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 		vdd-apc-supply = <&pm8110_s2>;
 
@@ -386,3 +391,7 @@
 		};
 	};
 };
+
+&pm8110_chg_batif {
+	regulator-name = "batfet";
+};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 2a619db..e560447 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -113,8 +113,8 @@
 			qcom,mode = "wfi";
 			qcom,l2 = "l2_cache_active";
 			qcom,latency-us = <1>;
-			qcom,ss-power = <784>;
-			qcom,energy-overhead = <190000>;
+			qcom,ss-power = <530>;
+			qcom,energy-overhead = <52800>;
 			qcom,time-overhead = <100>;
 		};
 
@@ -122,30 +122,30 @@
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
 			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <3000>;
-			qcom,ss-power = <725>;
-			qcom,energy-overhead = <99500>;
-			qcom,time-overhead = <3130>;
+			qcom,latency-us = <500>;
+			qcom,ss-power = <410>;
+			qcom,energy-overhead = <603400>;
+			qcom,time-overhead = <1200>;
 		};
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <138>;
-			qcom,energy-overhead = <1208400>;
-			qcom,time-overhead = <9200>;
+			qcom,latency-us = <520>;
+			qcom,ss-power = <460>;
+			qcom,energy-overhead = <704900>;
+			qcom,time-overhead = <1300>;
 		};
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <30000>;
-			qcom,ss-power = <110>;
-			qcom,energy-overhead = <1250300>;
-			qcom,time-overhead = <9500>;
+			qcom,latency-us = <11700>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
 		};
 	};
 
@@ -168,6 +168,7 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<41 63>,  /* dino_gen_purpose_irq35 */
 			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
 			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
 			<0xff 35>,  /* WDT_barkInt */
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 257d7a4..72509c1 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -115,8 +115,8 @@
 			qcom,mode = "wfi";
 			qcom,l2 = "l2_cache_active";
 			qcom,latency-us = <1>;
-			qcom,ss-power = <784>;
-			qcom,energy-overhead = <190000>;
+			qcom,ss-power = <530>;
+			qcom,energy-overhead = <52800>;
 			qcom,time-overhead = <100>;
 		};
 
@@ -124,30 +124,30 @@
 			reg = <0x1>;
 			qcom,mode = "standalone_pc";
 			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <3000>;
-			qcom,ss-power = <725>;
-			qcom,energy-overhead = <99500>;
-			qcom,time-overhead = <3130>;
+			qcom,latency-us = <500>;
+			qcom,ss-power = <410>;
+			qcom,energy-overhead = <603400>;
+			qcom,time-overhead = <1200>;
 		};
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_gdhs";
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <138>;
-			qcom,energy-overhead = <1208400>;
-			qcom,time-overhead = <9200>;
+			qcom,latency-us = <10700>;
+			qcom,ss-power = <325>;
+			qcom,energy-overhead = <441250>;
+			qcom,time-overhead = <1020>;
 		};
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
 			qcom,mode = "pc";
 			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <30000>;
-			qcom,ss-power = <110>;
-			qcom,energy-overhead = <1250300>;
-			qcom,time-overhead = <9500>;
+			qcom,latency-us = <11700>;
+			qcom,ss-power = <315>;
+			qcom,energy-overhead = <1027150>;
+			qcom,time-overhead = <2400>;
 		};
 	};
 
@@ -170,6 +170,7 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<41 63>,  /* dino_gen_purpose_irq35 */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 7dcb985..b0f9d62 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -795,6 +795,10 @@
 		qcom,core-limit-temp = <80>;
 		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <0xe>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor5",
+				"tsens_tz_sensor5", "tsens_tz_sensor5";
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
 		vdd-dig-supply = <&pm8110_s1_floor_corner>;
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..a85e048
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+&soc {
+
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
+	};
+};
+
+&cci {
+
+	actuator0: qcom,actuator@6e {
+		cell-index = <5>;
+		reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@20 {
+		compatible = "ovti,ov8865";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x300b 0x8865>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "ov8865_q8v18a";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+		                                         "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 37 0>,
+		        <&msmgpio 36 0>,
+		        <&msmgpio 15 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-af-pwdm = <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_RESET1",
+		        "CAM_STANDBY",
+		        "CAM_AF_PWDM";
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@6a {
+		compatible = "ovti,ov5648";
+		reg = <0x6a>;
+		qcom,slave-id = <0x6c 0x300a 0x5648>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		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,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+				<&msmgpio 28 0>,
+				<&msmgpio 35 0>,
+				<&msmgpio 23 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,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-cdp.dts
index 7d8d6cf..d6e70e6 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-cdp.dts
@@ -32,3 +32,7 @@
 	};
 
 };
+
+&hsic_host {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
index b7826e5..6d907ef 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 /include/ "msm8926.dtsi"
 /include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-camera-sensor-qrd.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 QRD SKUG";
@@ -35,6 +36,69 @@
 	qcom,battery-data = <&qrd_batterydata>;
 };
 
+&soc {
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		focaltech@38 {
+			compatible = "focaltech,5x06";
+			reg = <0x38>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			focaltech,name = "ft5336";
+			focaltech,family-id = <0x14>;
+			focaltech,reset-gpio = <&msmgpio 16 0x00>;
+			focaltech,irq-gpio = <&msmgpio 17 0x00>;
+			focaltech,display-coords = <0 0 720 1280>;
+			focaltech,panel-coords = <0 0 720 1400>;
+			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 = <200>;
+			focaltech,num-max-touches = <5>;
+			focaltech,fw-name = "ft_8926_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <30>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
+			focaltech,fw-auto-cal;
+			focaltech,ignore-id-check;
+		};
+	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "ft5x06_ts";
+		qcom,disp-maxx = <720>;
+		qcom,disp-maxy = <1280>;
+		qcom,panel-maxx = <720>;
+		qcom,panel-maxy = <1404>;
+		qcom,key-codes = <139 172 158>;
+		qcom,y-offset = <0>;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		keypad-backlight {
+			gpios = <&msmgpio 34 0>;
+			label = "button-backlight";
+			linux,default-trigger = "none";
+		};
+	};
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a100 {
+			status = "disable";
+			};
+		};
+};
+
 &mdss_dsi0 {
 	qcom,dsi-pref-prim-pan = <&dsi_ssd2080m_720_vid>;
 };
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 5893a9b..bbddec3 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -44,32 +44,86 @@
 			<0xfc4b80b0 0x8>;
 		reg-names = "rcg_base", "pte_efuse";
 	};
+
+	qcom,msm-thermal {
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor5",
+				"tsens_tz_sensor1", "tsens_tz_sensor1";
+	};
+
+	qcom,mpm@fc4281d0 {
+		qcom,gpio-map = <3  1>,
+			<4  4 >,
+			<5  5 >,
+			<6  9 >,
+			<7  13>,
+			<8  17>,
+			<9  21>,
+			<10  27>,
+			<11  29>,
+			<12  31>,
+			<13  33>,
+			<14  35>,
+			<15  37>,
+			<16  38>,
+			<17  39>,
+			<18  41>,
+			<19  46>,
+			<20  48>,
+			<21  49>,
+			<22  50>,
+			<23  51>,
+			<24  52>,
+			<25  54>,
+			<26  62>,
+			<27  63>,
+			<28  64>,
+			<29  65>,
+			<30  66>,
+			<31  67>,
+			<32  68>,
+			<33  69>,
+			<34  71>,
+			<35  72>,
+			<36  106>,
+			<37  107>,
+			<38  108>,
+			<39  109>,
+			<40  110>,
+			<41  119>,
+			<54  111>,
+			<55  113>;
+	};
 };
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+	qcom,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
@@ -84,10 +138,18 @@
 };
 
 &msmgpio {
-	ngpio = <120>;
+	ngpio = <121>;
 };
 
 &memory_hole {
 	qcom,memblock-remove = <0x08000000 0x7500000
 				0x0fa00000 0x500000>; /* Address and size of the hole */
 };
+
+&hsic_host {
+	interrupt-map = <0 &intc 0 136 0
+		1 &intc 0 148 0
+		2 &msmgpio 119 0x8>;
+	hsic,strobe-gpio = <&msmgpio 119 0x00>;
+	hsic,data-gpio = <&msmgpio 120 0x00>;
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 9cbd45c..c84dfe5 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -78,6 +78,7 @@
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "imx135";
 		qcom,actuator-src = <&actuator1>;
+		qcom,led-flash-src = <&led_flash0>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 68af4a6..02d2288 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -78,6 +78,7 @@
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "imx135";
 		qcom,actuator-src = <&actuator1>;
+		qcom,led-flash-src = <&led_flash0>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index d200100..9e7b2e6 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -41,6 +41,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -227,7 +243,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8841_s2>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -236,6 +252,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		qcom,phy-susp-sof-workaround;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index d02021c..c112bea 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -37,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 73aba8f..67e1802 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -397,7 +397,7 @@
 		                1 &intc 0 148 0
 		                2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -405,6 +405,7 @@
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
 			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
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 24b5860..6d5000f 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -64,6 +64,7 @@
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
 			qcom,memory-reservation-size = <0x800000>;
+			qcom,memblock-reserve = <0x03200000 0x01E00000>;
 		};
 
 		mdss_fb1: qcom,mdss_fb_external {
@@ -89,7 +90,6 @@
 		qcom,mdss-mdp = <&mdss_mdp>;
 		qcom,platform-reset-gpio = <&pm8941_gpios 19 0>;
 		qcom,platform-enable-gpio = <&msmgpio 58 0>;
-		qcom,platform-reset-sequence = <1 20 0 200 1 20 2>;
 		qcom,platform-te-gpio = <&msmgpio 12 0>;
 		qcom,platform-strength-ctrl = [ff 06];
 		qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 22fff80..b88fbdc 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -37,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -358,6 +374,16 @@
 	qcom,otg-capability;
 };
 
+/ {
+	mtp_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-palladium.dtsi"
+		/include/ "batterydata-mtp-3000mah.dtsi"
+	};
+};
+
 &pm8941_bms {
 	qcom,enable-fcc-learning;
 	qcom,min-fcc-learning-soc = <20>;
@@ -365,11 +391,13 @@
 	qcom,min-fcc-learning-samples = <5>;
 	qcom,fcc-resolution = <10>;
 	status = "ok";
+	qcom,battery-data = <&mtp_batterydata>;
 };
 
 &pm8941_chg {
 	status = "ok";
 	qcom,charging-disabled;
+	qcom,battery-data = <&mtp_batterydata>;
 
 	qcom,chgr@1000 {
 		status = "ok";
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index a88a709..344c26f 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -560,6 +560,10 @@
 	regulator-name = "8941_smbb_boost";
 };
 
+&pm8941_chg_batif  {
+	regulator-name = "batfet";
+};
+
 &pm8941_chg_otg {
 	regulator-name = "8941_smbb_otg";
 };
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index c3fd98d..071c7c9 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -26,6 +26,8 @@
 &ehci {
 	status = "ok";
 	vbus-supply = <&usb2_otg_sw>;
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
 };
 
 &hsic_host {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 65307ae..3057e6e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -77,7 +77,7 @@
 
 		adsp_mem: adsp_region {
 			linux,contiguous-region;
-			reg = <0 0x2F00000>;
+			reg = <0 0x3F00000>;
 			label = "adsp_mem";
 		};
 
@@ -220,7 +220,7 @@
 	qcom,vidc {
 		compatible = "qcom,msm-vidc";
 		qcom,hfi = "q6";
-		qcom,max-hw-load = <108000>; /* 720p @ 30 */
+		qcom,max-hw-load = <243000>; /* 1080p @ 30 */
 	};
 
 	qcom,wfd {
@@ -629,10 +629,10 @@
 			"MSM_TSIF1_PHYS",
 			"MSM_TSPP_PHYS",
 			"MSM_TSPP_BAM_PHYS";
-		interrupts = <0 153 0>, /* TSIF_TSPP_IRQ */
-			<0 151 0>, /* TSIF0_IRQ */
-			<0 152 0>, /* TSIF1_IRQ */
-			<0 154 0>; /* TSIF_BAM_IRQ */
+		interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */
+			<0 119 0>, /* TSIF0_IRQ */
+			<0 120 0>, /* TSIF1_IRQ */
+			<0 122 0>; /* TSIF_BAM_IRQ */
 		interrupt-names = "TSIF_TSPP_IRQ",
 			"TSIF0_IRQ",
 			"TSIF1_IRQ",
@@ -659,7 +659,6 @@
 
 		qcom,msm-bus,name = "tsif";
 		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
 				<82 512 0 0>, /* No vote */
@@ -835,9 +834,11 @@
 		reg-names = "qup_phys_addr";
 		interrupts = <0 96 0>;
 		interrupt-names = "qup_err_intr";
-		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <50000000>;
+		qcom,i2c-bus-freq = <384000>;
+		qcom,i2c-src-freq = <19200000>;
 		qcom,master-id = <86>;
+		qcom,scl-gpio = <&msmgpio 7 0>;
+		qcom,sda-gpio = <&msmgpio 6 0>;
 	};
 
 	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -1559,7 +1560,8 @@
 
         memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
-                qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
+                qcom,memblock-remove = <0x5d00000 0x7d00000
+					0xfa00000 0x500000>; /* Address and Size of Hole */
         };
 
 	uart7: uart@f995d000 { /*BLSP #2, UART #7 */
diff --git a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
similarity index 63%
rename from arch/arm/boot/dts/msm8974pro-ab-cdp.dts
rename to arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
index fae72fa..b6a6fcb 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
@@ -12,21 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
 /include/ "msm8974-cdp.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro CDP";
+	model = "Qualcomm MSM 8974Pro-AA/AB CDP";
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
-	qcom,msm-id = <209 1 0x10000>,
-		      <211 1 0x10000>,
-		      <212 1 0x10000>,
-		      <214 1 0x10000>,
-		      <215 1 0x10000>,
-		      <217 1 0x10000>,
-		      <218 1 0x10000>,
-		      <194 1 0x10000>,	/* 8974Pro-AC IDs */
-		      <210 1 0x10000>,
-		      <213 1 0x10000>,
-		      <216 1 0x10000>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
similarity index 71%
rename from arch/arm/boot/dts/msm8974pro-ab-fluid.dts
rename to arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
index 9a31834..be298d1 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
@@ -12,17 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
 /include/ "msm8974-fluid.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro FLUID";
+	model = "Qualcomm MSM 8974Pro-AA/AB FLUID";
 	compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
-	qcom,msm-id = <209 3 0x10000>,
-		      <211 3 0x10000>,
-		      <212 3 0x10000>,
-		      <214 3 0x10000>,
-		      <215 3 0x10000>,
-		      <217 3 0x10000>,
-		      <218 3 0x10000>;
+	qcom,board-id = <3 0>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
similarity index 71%
rename from arch/arm/boot/dts/msm8974pro-ab-liquid.dts
rename to arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
index 0ec9d8a..49c3df0 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
@@ -12,17 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
 /include/ "msm8974-liquid.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro LIQUID";
+	model = "Qualcomm MSM 8974Pro-AA/AB LIQUID";
 	compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
-	qcom,msm-id = <209 9 0x10000>,
-		      <211 9 0x10000>,
-		      <212 9 0x10000>,
-		      <214 9 0x10000>,
-		      <215 9 0x10000>,
-		      <217 9 0x10000>,
-		      <218 9 0x10000>;
+	qcom,board-id = <9 0>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
similarity index 71%
rename from arch/arm/boot/dts/msm8974pro-ab-mtp.dts
rename to arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index 002baf7..fa313bf 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -12,17 +12,15 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
 /include/ "msm8974-mtp.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro MTP";
+	model = "Qualcomm MSM 8974Pro-AA/AB MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
-	qcom,msm-id = <209 8 0x10000>,
-		      <211 8 0x10000>,
-		      <212 8 0x10000>,
-		      <214 8 0x10000>,
-		      <215 8 0x10000>,
-		      <217 8 0x10000>,
-		      <218 8 0x10000>;
+	qcom,board-id = <8 0>;
+};
+
+&sdhc_1 {
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
similarity index 60%
copy from arch/arm/boot/dts/msm8974pro-ab-mtp.dts
copy to arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
index 002baf7..a44bc56 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
@@ -10,19 +10,15 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-mtp.dtsi"
+/include/ "msm8974pro-pm8941.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro MTP";
-	compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
-	qcom,msm-id = <209 8 0x10000>,
-		      <211 8 0x10000>,
-		      <212 8 0x10000>,
-		      <214 8 0x10000>,
-		      <215 8 0x10000>,
-		      <217 8 0x10000>,
-		      <218 8 0x10000>;
+	qcom,msm-id = <208 0x10000>,
+		      <209 0x10000>,
+		      <211 0x10000>,
+		      <212 0x10000>,
+		      <214 0x10000>,
+		      <215 0x10000>,
+		      <217 0x10000>,
+		      <218 0x10000>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
similarity index 63%
copy from arch/arm/boot/dts/msm8974pro-ab-cdp.dts
copy to arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
index fae72fa..3e0feda 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
@@ -12,21 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ac-pm8941.dtsi"
 /include/ "msm8974-cdp.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro CDP";
+	model = "Qualcomm MSM 8974Pro-AC CDP";
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
-	qcom,msm-id = <209 1 0x10000>,
-		      <211 1 0x10000>,
-		      <212 1 0x10000>,
-		      <214 1 0x10000>,
-		      <215 1 0x10000>,
-		      <217 1 0x10000>,
-		      <218 1 0x10000>,
-		      <194 1 0x10000>,	/* 8974Pro-AC IDs */
-		      <210 1 0x10000>,
-		      <213 1 0x10000>,
-		      <216 1 0x10000>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
similarity index 71%
copy from arch/arm/boot/dts/msm8974pro-ab-liquid.dts
copy to arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
index 0ec9d8a..7b88abe 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
@@ -12,17 +12,11 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ac-pm8941.dtsi"
 /include/ "msm8974-liquid.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro LIQUID";
+	model = "Qualcomm MSM 8974Pro-AC LIQUID";
 	compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
-	qcom,msm-id = <209 9 0x10000>,
-		      <211 9 0x10000>,
-		      <212 9 0x10000>,
-		      <214 9 0x10000>,
-		      <215 9 0x10000>,
-		      <217 9 0x10000>,
-		      <218 9 0x10000>;
+	qcom,board-id = <9 0>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
new file mode 100644
index 0000000..f79d361
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
@@ -0,0 +1,30 @@
+/* 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/ "msm8974pro-ac-pm8941.dtsi"
+/include/ "msm8974-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8974Pro-AC MTP";
+	compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
+	qcom,board-id = <8 0>;
+};
+
+&sdhc_1 {
+	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 */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
index cc4b6ed..cdcfecb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
@@ -10,243 +10,15 @@
  * GNU General Public License for more details.
  */
 
-/include/ "msm8974pro-ac.dtsi"
-&spmi_bus {
-	pm8941_lsid0: qcom,pm8941@2 {
-		reg = <0x2>;
-	};
-	pm8941_lsid1: qcom,pm8941@3 {
-		reg = <0x3>;
-	};
-};
-/include/ "msm-pm8941.dtsi"
+/include/ "msm8974pro-pm8941.dtsi"
 
-&pm8941_lsid0 {
-	qcom,power-on@800 {
-		status = "disabled";
-	};
-
-	clkdiv@5b00 {
-		status = "disabled";
-	};
-
-	clkdiv@5c00 {
-		status = "disabled";
-	};
-
-	clkdiv@5d00 {
-		status = "disabled";
-	};
-
-	qcom,pm8941_rtc {
-		status = "disabled";
-	};
-
-	gpios {
-		status = "disabled";
-	};
-
-	mpps {
-		status = "disabled";
-	};
+/ {
+	qcom,msm-id = <194 0x10000>,
+		      <210 0x10000>,
+		      <213 0x10000>,
+		      <216 0x10000>;
 };
 
-&pm8941_lsid1 {
-	pm8941_boost: regulator@a000 {
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-		qcom,enable-time = <500>;
-		status = "okay";
-	};
-
-	pm8941_mvs1: regulator@8300 {
-		parent-supply = <&pm8941_chg_otg>;
-		qcom,enable-time = <1000>;
-		qcom,pull-down-enable = <1>;
-		interrupts = <0x3 0x83 0x2>;
-		interrupt-names = "ocp";
-		qcom,ocp-enable = <1>;
-		qcom,ocp-max-retries = <10>;
-		qcom,ocp-retry-delay = <30>;
-		qcom,soft-start-enable = <1>;
-		qcom,vs-soft-start-strength = <0>;
-		qcom,hpm-enable = <1>;
-		qcom,auto-mode-enable = <0>;
-		status = "okay";
-	};
-};
-
-&pma8084_mvs1 {
-	parent-supply = <&pm8941_boost>;
-};
-
-&pm8941_chg {
-	otg-parent-supply = <&pm8941_boost>;
-};
-
-&pm8941_chg_boost {
-	regulator-min-microvolt = <5000000>;
-	regulator-max-microvolt = <5000000>;
-	regulator-name = "8941_smbb_boost";
-};
-
-&pm8941_chg_otg {
-	regulator-name = "8941_smbb_otg";
-};
-
-&usb3 {
-	vbus_dwc3-supply = <&pm8941_mvs1>;
-	qcom,misc-ref = <&pm8941_misc>;
-	dwc_usb3-adc_tm = <&pm8941_adc_tm>;
-	interrupt-map-mask = <0x0 0xffffffff>;
-	interrupt-map = <0x0 0 &intc 0 133 0
-			0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
-	interrupt-names = "hs_phy_irq", "pmic_id_irq";
-};
-
-/* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
-&pm8941_lsid0 {
-	qcom,temp-alarm@2400 {
-		interrupts = <0x2 0x24 0x0>;
-	};
-
-	qcom,power-on@800 {
-		interrupts = <0x2 0x8 0x0>,
-			     <0x2 0x8 0x1>,
-			     <0x2 0x8 0x4>,
-			     <0x2 0x8 0x5>;
-		interrupt-names = "kpdpwr", "resin",
-				"resin-bark", "kpdpwr-resin-bark";
-	};
-
-	qcom,bsi@1b00 {
-		interrupts = <0x2 0x1b 0x0>,
-			     <0x2 0x1b 0x1>,
-			     <0x2 0x1b 0x2>,
-			     <0x2 0x12 0x0>;
-		interrupt-names = "err",
-				  "rx",
-				  "tx",
-				  "batt-present";
-	};
-
-	qcom,bms {
-		qcom,bms-bms@4000 {
-			interrupts =	<0x2 0x40 0x0>,
-					<0x2 0x40 0x1>,
-					<0x2 0x40 0x2>,
-					<0x2 0x40 0x3>,
-					<0x2 0x40 0x4>,
-					<0x2 0x40 0x5>,
-					<0x2 0x40 0x6>,
-					<0x2 0x40 0x7>;
-			interrupt-names = "cc_thr",
-					  "ocv_for_r",
-					  "good_ocv",
-					  "charge_begin",
-					  "ocv_thr",
-					  "sw_cc_thr",
-					  "vsense_avg",
-					  "vsense_for_r";
-		};
-	};
-
-	qcom,charger {
-		qcom,chgr@1000 {
-			interrupts =	<0x2 0x10 0x0>,
-					<0x2 0x10 0x1>,
-					<0x2 0x10 0x2>,
-					<0x2 0x10 0x3>,
-					<0x2 0x10 0x4>,
-					<0x2 0x10 0x5>,
-					<0x2 0x10 0x6>,
-					<0x2 0x10 0x7>;
-			interrupt-names =	"vbat-det-lo",
-						"vbat-det-hi",
-						"chgwdog",
-						"state-change",
-						"trkl-chg-on",
-						"fast-chg-on",
-						"chg-failed",
-						"chg-done";
-		};
-
-		qcom,buck@1100 {
-			interrupts =	<0x2 0x11 0x0>,
-					<0x2 0x11 0x1>,
-					<0x2 0x11 0x2>,
-					<0x2 0x11 0x3>,
-					<0x2 0x11 0x4>,
-					<0x2 0x11 0x5>,
-					<0x2 0x11 0x6>;
-			interrupt-names =	"vbat-ov",
-						"vreg-ov",
-						"overtemp",
-						"vchg-loop",
-						"ichg-loop",
-						"ibat-loop",
-						"vdd-loop";
-		};
-
-		qcom,bat-if@1200 {
-			interrupts =	<0x2 0x12 0x0>,
-					<0x2 0x12 0x1>,
-					<0x2 0x12 0x2>,
-					<0x2 0x12 0x3>,
-					<0x2 0x12 0x4>;
-			interrupt-names =	"batt-pres",
-						"bat-temp-ok",
-						"bat-fet-on",
-						"vcp-on",
-						"psi";
-		};
-
-		qcom,usb-chgpth@1300 {
-			interrupts =	<0x2 0x13 0x0>,
-					<0x2 0x13 0x1>,
-					<0x2 0x13 0x2>;
-			interrupt-names =	"coarse-det-usb",
-						"usbin-valid",
-						"chg-gone";
-		};
-
-		qcom,dc-chgpth@1400 {
-			interrupts =	<0x2 0x14 0x0>,
-					<0x2 0x14 0x1>;
-			interrupt-names =	"coarse-det-dc",
-						"dcin-valid";
-		};
-
-		qcom,boost@1500 {
-			interrupts =	<0x2 0x15 0x0>,
-					<0x2 0x15 0x1>;
-			interrupt-names =	"boost-pwr-ok",
-						"limit-error";
-		};
-	};
-
-	qcom,pm8941_rtc {
-		qcom,pm8941_rtc_alarm@6100 {
-			interrupts = <0x2 0x61 0x1>;
-		};
-	};
-
-	vadc@3100 {
-		interrupts = <0x2 0x31 0x0>;
-		interrupt-names = "eoc-int-en-set";
-	};
-
-	iadc@3600 {
-		interrupts = <0x2 0x36 0x0>;
-		interrupt-names = "eoc-int-en-set";
-	};
-
-	qcom,vadc@3400 {
-		interrupts =	<0x2 0x34 0x0>,
-				<0x2 0x34 0x3>,
-				<0x2 0x34 0x4>;
-		interrupt-names =	"eoc-int-en-set",
-					"high-thr-en-set",
-					"low-thr-en-set";
-	};
+&sdhc_1 {
+	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
similarity index 82%
rename from arch/arm/boot/dts/msm8974pro-ac-mtp.dts
rename to arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
index 237c9f9..8a4ad45 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
@@ -12,16 +12,13 @@
 
 /dts-v1/;
 
-/include/ "msm8974pro-ac-pm8941.dtsi"
-/include/ "msm8974pro-ac-mtp.dtsi"
+/include/ "msm8974pro-ac-pma8084-pm8941.dtsi"
+/include/ "msm8974pro-pma8084-mtp.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro-AC MTP";
+	model = "Qualcomm MSM 8974Pro-AC + PMA8084 MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
-	qcom,msm-id = <194 8 0x10000>,
-		      <210 8 0x10000>,
-		      <213 8 0x10000>,
-		      <216 8 0x10000>;
+	qcom,board-id = <8 1>;
 };
 
 &pma8084_vadc {
@@ -123,12 +120,3 @@
 		qcom,thermal-node;
 	};
 };
-
-&sdhc_1 {
-	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 400000000>;
-	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 */
-	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
-};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
new file mode 100644
index 0000000..746702b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
@@ -0,0 +1,256 @@
+/* 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/ "msm8974pro-ac-pma8084.dtsi"
+&spmi_bus {
+	pm8941_lsid0: qcom,pm8941@2 {
+		reg = <0x2>;
+	};
+	pm8941_lsid1: qcom,pm8941@3 {
+		reg = <0x3>;
+	};
+};
+/include/ "msm-pm8941.dtsi"
+
+&pm8941_lsid0 {
+	qcom,power-on@800 {
+		status = "disabled";
+	};
+
+	clkdiv@5b00 {
+		status = "disabled";
+	};
+
+	clkdiv@5c00 {
+		status = "disabled";
+	};
+
+	clkdiv@5d00 {
+		status = "disabled";
+	};
+
+	qcom,pm8941_rtc {
+		status = "disabled";
+	};
+
+	gpios {
+		status = "disabled";
+	};
+
+	mpps {
+		status = "disabled";
+	};
+};
+
+&pm8941_lsid1 {
+	pm8941_boost: regulator@a000 {
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		qcom,enable-time = <500>;
+		status = "okay";
+	};
+
+	pm8941_mvs1: regulator@8300 {
+		parent-supply = <&pm8941_chg_otg>;
+		qcom,enable-time = <1000>;
+		qcom,pull-down-enable = <1>;
+		interrupts = <0x3 0x83 0x2>;
+		interrupt-names = "ocp";
+		qcom,ocp-enable = <1>;
+		qcom,ocp-max-retries = <10>;
+		qcom,ocp-retry-delay = <30>;
+		qcom,soft-start-enable = <1>;
+		qcom,vs-soft-start-strength = <0>;
+		qcom,hpm-enable = <1>;
+		qcom,auto-mode-enable = <0>;
+		status = "okay";
+	};
+};
+
+&pma8084_mvs1 {
+	parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg {
+	otg-parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg_boost {
+	regulator-min-microvolt = <5000000>;
+	regulator-max-microvolt = <5000000>;
+	regulator-name = "8941_smbb_boost";
+};
+
+&pm8941_chg_batif {
+	regulator-name = "batfet";
+};
+
+&pm8941_chg_otg {
+	regulator-name = "8941_smbb_otg";
+};
+
+&usb3 {
+	vbus_dwc3-supply = <&pm8941_mvs1>;
+	qcom,misc-ref = <&pm8941_misc>;
+	dwc_usb3-adc_tm = <&pm8941_adc_tm>;
+	interrupt-map-mask = <0x0 0xffffffff>;
+	interrupt-map = <0x0 0 &intc 0 133 0
+			0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
+	interrupt-names = "hs_phy_irq", "pmic_id_irq";
+};
+
+/* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
+&pm8941_lsid0 {
+	qcom,temp-alarm@2400 {
+		interrupts = <0x2 0x24 0x0>;
+	};
+
+	qcom,power-on@800 {
+		interrupts = <0x2 0x8 0x0>,
+			     <0x2 0x8 0x1>,
+			     <0x2 0x8 0x4>,
+			     <0x2 0x8 0x5>;
+		interrupt-names = "kpdpwr", "resin",
+				"resin-bark", "kpdpwr-resin-bark";
+	};
+
+	qcom,bsi@1b00 {
+		interrupts = <0x2 0x1b 0x0>,
+			     <0x2 0x1b 0x1>,
+			     <0x2 0x1b 0x2>,
+			     <0x2 0x12 0x0>;
+		interrupt-names = "err",
+				  "rx",
+				  "tx",
+				  "batt-present";
+	};
+
+	qcom,bms {
+		qcom,bms-bms@4000 {
+			interrupts =	<0x2 0x40 0x0>,
+					<0x2 0x40 0x1>,
+					<0x2 0x40 0x2>,
+					<0x2 0x40 0x3>,
+					<0x2 0x40 0x4>,
+					<0x2 0x40 0x5>,
+					<0x2 0x40 0x6>,
+					<0x2 0x40 0x7>;
+			interrupt-names = "cc_thr",
+					  "ocv_for_r",
+					  "good_ocv",
+					  "charge_begin",
+					  "ocv_thr",
+					  "sw_cc_thr",
+					  "vsense_avg",
+					  "vsense_for_r";
+		};
+	};
+
+	qcom,charger {
+		qcom,chgr@1000 {
+			interrupts =	<0x2 0x10 0x0>,
+					<0x2 0x10 0x1>,
+					<0x2 0x10 0x2>,
+					<0x2 0x10 0x3>,
+					<0x2 0x10 0x4>,
+					<0x2 0x10 0x5>,
+					<0x2 0x10 0x6>,
+					<0x2 0x10 0x7>;
+			interrupt-names =	"vbat-det-lo",
+						"vbat-det-hi",
+						"chgwdog",
+						"state-change",
+						"trkl-chg-on",
+						"fast-chg-on",
+						"chg-failed",
+						"chg-done";
+		};
+
+		qcom,buck@1100 {
+			interrupts =	<0x2 0x11 0x0>,
+					<0x2 0x11 0x1>,
+					<0x2 0x11 0x2>,
+					<0x2 0x11 0x3>,
+					<0x2 0x11 0x4>,
+					<0x2 0x11 0x5>,
+					<0x2 0x11 0x6>;
+			interrupt-names =	"vbat-ov",
+						"vreg-ov",
+						"overtemp",
+						"vchg-loop",
+						"ichg-loop",
+						"ibat-loop",
+						"vdd-loop";
+		};
+
+		qcom,bat-if@1200 {
+			interrupts =	<0x2 0x12 0x0>,
+					<0x2 0x12 0x1>,
+					<0x2 0x12 0x2>,
+					<0x2 0x12 0x3>,
+					<0x2 0x12 0x4>;
+			interrupt-names =	"batt-pres",
+						"bat-temp-ok",
+						"bat-fet-on",
+						"vcp-on",
+						"psi";
+		};
+
+		qcom,usb-chgpth@1300 {
+			interrupts =	<0x2 0x13 0x0>,
+					<0x2 0x13 0x1>,
+					<0x2 0x13 0x2>;
+			interrupt-names =	"coarse-det-usb",
+						"usbin-valid",
+						"chg-gone";
+		};
+
+		qcom,dc-chgpth@1400 {
+			interrupts =	<0x2 0x14 0x0>,
+					<0x2 0x14 0x1>;
+			interrupt-names =	"coarse-det-dc",
+						"dcin-valid";
+		};
+
+		qcom,boost@1500 {
+			interrupts =	<0x2 0x15 0x0>,
+					<0x2 0x15 0x1>;
+			interrupt-names =	"boost-pwr-ok",
+						"limit-error";
+		};
+	};
+
+	qcom,pm8941_rtc {
+		qcom,pm8941_rtc_alarm@6100 {
+			interrupts = <0x2 0x61 0x1>;
+		};
+	};
+
+	vadc@3100 {
+		interrupts = <0x2 0x31 0x0>;
+		interrupt-names = "eoc-int-en-set";
+	};
+
+	iadc@3600 {
+		interrupts = <0x2 0x36 0x0>;
+		interrupt-names = "eoc-int-en-set";
+	};
+
+	qcom,vadc@3400 {
+		interrupts =	<0x2 0x34 0x0>,
+				<0x2 0x34 0x3>,
+				<0x2 0x34 0x4>;
+		interrupt-names =	"eoc-int-en-set",
+					"high-thr-en-set",
+					"low-thr-en-set";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
similarity index 60%
copy from arch/arm/boot/dts/msm8974pro-ab-mtp.dts
copy to arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
index 002baf7..4b7ed1d 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
@@ -10,19 +10,15 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-mtp.dtsi"
+/include/ "msm8974pro-pma8084.dtsi"
 
 / {
-	model = "Qualcomm MSM 8974Pro MTP";
-	compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
-	qcom,msm-id = <209 8 0x10000>,
-		      <211 8 0x10000>,
-		      <212 8 0x10000>,
-		      <214 8 0x10000>,
-		      <215 8 0x10000>,
-		      <217 8 0x10000>,
-		      <218 8 0x10000>;
+	qcom,msm-id = <194 0x10000>,
+		      <210 0x10000>,
+		      <213 0x10000>,
+		      <216 0x10000>;
+};
+
+&sdhc_1 {
+	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ion.dtsi b/arch/arm/boot/dts/msm8974pro-ion.dtsi
index 7faee21..4c427bf 100644
--- a/arch/arm/boot/dts/msm8974pro-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ion.dtsi
@@ -17,7 +17,7 @@
 			compatible = "qcom,msm-ion-reserve";
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
-			qcom,memory-fixed = <0x05400000 0x2700000>;
+			qcom,memory-fixed = <0x05a00000 0x2100000>;
 		};
 
 		qcom,ion-heap@26 { /* MODEM HEAP */
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
similarity index 84%
rename from arch/arm/boot/dts/msm8974pro-ab.dtsi
rename to arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 5809069..0f37584 100644
--- a/arch/arm/boot/dts/msm8974pro-ab.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -36,6 +36,22 @@
 	qcom,use-phase-switching;
 };
 
+&krait0_vreg {
+		regulator-max-microvolt = <1120000>;
+};
+
+&krait1_vreg {
+		regulator-max-microvolt = <1120000>;
+};
+
+&krait2_vreg {
+		regulator-max-microvolt = <1120000>;
+};
+
+&krait3_vreg {
+		regulator-max-microvolt = <1120000>;
+};
+
 &tspp {
 	vdd_cx-supply = <&pm8841_s2_corner>;
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
similarity index 93%
rename from arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
rename to arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
index debf7fb..26fdebb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -46,6 +46,11 @@
 
 &soc {
 	i2c@f9924000 {
+		synaptics@20 {
+			vdd-supply = <&pma8084_l18>;
+			vcc_i2c-supply = <&pma8084_lvs1>;
+		};
+
 		atmel_mxt_ts@4a {
 			vdd_ana-supply = <&pma8084_l18>;
 			vcc_i2c-supply = <&pma8084_lvs1>;
@@ -86,6 +91,12 @@
 &sdhc_1 {
 	vdd-supply = <&pma8084_l20>;
 	vdd-io-supply = <&pma8084_s4>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 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 */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 };
 
 &sdhc_2 {
diff --git a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
similarity index 98%
rename from arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
rename to arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index e0473b7..c38c9e1 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
@@ -488,7 +488,7 @@
 				<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
 			reg-names = "acs", "mdd";
 			regulator-min-microvolt = <500000>;
-			regulator-max-microvolt = <1100000>;
+			regulator-max-microvolt = <1120000>;
 			qcom,headroom-voltage = <150000>;
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
@@ -504,7 +504,7 @@
 				<0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */
 			reg-names = "acs", "mdd";
 			regulator-min-microvolt = <500000>;
-			regulator-max-microvolt = <1100000>;
+			regulator-max-microvolt = <1120000>;
 			qcom,headroom-voltage = <150000>;
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
@@ -520,7 +520,7 @@
 				<0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */
 			reg-names = "acs", "mdd";
 			regulator-min-microvolt = <500000>;
-			regulator-max-microvolt = <1100000>;
+			regulator-max-microvolt = <1120000>;
 			qcom,headroom-voltage = <150000>;
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
@@ -536,7 +536,7 @@
 				<0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */
 			reg-names = "acs", "mdd";
 			regulator-min-microvolt = <500000>;
-			regulator-max-microvolt = <1100000>;
+			regulator-max-microvolt = <1120000>;
 			qcom,headroom-voltage = <150000>;
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
similarity index 98%
rename from arch/arm/boot/dts/msm8974pro-ac.dtsi
rename to arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index f8a371d..cd485c5 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -20,7 +20,7 @@
 
 /include/ "msm-pma8084-rpm-regulator.dtsi"
 /include/ "msm-pma8084.dtsi"
-/include/ "msm8974pro-ac-regulator.dtsi"
+/include/ "msm8974pro-pma8084-regulator.dtsi"
 
 /*
  * Override PM8841 and PM8941 resources with proper PMA8084 resources for
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 86f0058..f45d75e 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -46,6 +46,8 @@
 	/* Updated chip ID */
 	qcom,chipid = <0x03030002>;
 
+	qcom,initial-pwrlevel = <6>;
+
 	/* Updated bus bandwidth requirements */
 	qcom,msm-bus,vectors-KBps =
 		/* Off */
@@ -69,41 +71,69 @@
 
                qcom,gpu-pwrlevel@0 {
                        reg = <0>;
-                       qcom,gpu-freq = <550000000>;
+                       qcom,gpu-freq = <578000000>;
                        qcom,bus-freq = <5>;
                        qcom,io-fraction = <33>;
                };
 
-               qcom,gpu-pwrlevel@1 {
-                       reg = <1>;
-                       qcom,gpu-freq = <320000000>;
+		qcom,gpu-pwrlevel@1 {
+			reg = <1>;
+			qcom,gpu-freq = <462400000>;
+			qcom,bus-freq = <4>;
+			qcom,io-fraction = <33>;
+		};
+
+		qcom,gpu-pwrlevel@2 {
+			reg = <2>;
+			qcom,gpu-freq = <462400000>;
+			qcom,bus-freq = <3>;
+			qcom,io-fraction = <66>;
+		};
+
+		qcom,gpu-pwrlevel@3 {
+			reg = <3>;
+			qcom,gpu-freq = <389000000>;
+			qcom,bus-freq = <4>;
+			qcom,io-fraction = <66>;
+		};
+
+		qcom,gpu-pwrlevel@4 {
+			reg = <4>;
+			qcom,gpu-freq = <389000000>;
+			qcom,bus-freq = <3>;
+			qcom,io-fraction = <66>;
+		};
+
+               qcom,gpu-pwrlevel@5 {
+                       reg = <5>;
+                       qcom,gpu-freq = <330000000>;
                        qcom,bus-freq = <4>;
                        qcom,io-fraction = <66>;
                };
 
-               qcom,gpu-pwrlevel@2 {
-                       reg = <2>;
-                       qcom,gpu-freq = <320000000>;
+               qcom,gpu-pwrlevel@6 {
+                       reg = <6>;
+                       qcom,gpu-freq = <330000000>;
                        qcom,bus-freq = <3>;
                        qcom,io-fraction = <66>;
                };
 
-               qcom,gpu-pwrlevel@3 {
-                       reg = <3>;
+               qcom,gpu-pwrlevel@7 {
+                       reg = <7>;
                        qcom,gpu-freq = <200000000>;
                        qcom,bus-freq = <2>;
                        qcom,io-fraction = <100>;
                };
 
-               qcom,gpu-pwrlevel@4 {
-                       reg = <4>;
+               qcom,gpu-pwrlevel@8 {
+                       reg = <8>;
                        qcom,gpu-freq = <200000000>;
                        qcom,bus-freq = <1>;
                        qcom,io-fraction = <100>;
                };
 
-               qcom,gpu-pwrlevel@5 {
-                       reg = <5>;
+               qcom,gpu-pwrlevel@9 {
+                       reg = <9>;
                        qcom,gpu-freq = <27000000>;
                        qcom,bus-freq = <0>;
                        qcom,io-fraction = <0>;
@@ -203,5 +233,6 @@
 };
 
 &memory_hole {
-	qcom,memblock-remove = <0x05400000 0xab00000>; /* Address and size of the hole */
+	qcom,memblock-remove = <0x05a00000 0x7800000
+				0x0fa00000 0x500000>; /* Address and size of the hole */
 };
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 66d66fc..7c1af1a 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -268,6 +268,7 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_SMB350_CHARGER=y
+CONFIG_SMB349_USB_CHARGER=y
 CONFIG_BATTERY_BQ28400=y
 CONFIG_QPNP_CHARGER=y
 CONFIG_BATTERY_BCL=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 9535e05..03ed61f 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_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
@@ -233,7 +234,6 @@
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
-CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_PPP=y
@@ -301,6 +301,7 @@
 CONFIG_OV8825=y
 CONFIG_OV12830=y
 CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -348,6 +349,7 @@
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
@@ -385,6 +387,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
@@ -446,3 +449,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 176a8a2..f953a70 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -83,6 +83,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
@@ -235,7 +236,6 @@
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
-CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_PPP=y
@@ -305,6 +305,7 @@
 CONFIG_OV8825=y
 CONFIG_OV12830=y
 CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -374,6 +375,7 @@
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
@@ -411,6 +413,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
@@ -497,3 +500,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 1a197a3..325aba1 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -234,6 +234,8 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
@@ -284,6 +286,7 @@
 CONFIG_HI256=y
 CONFIG_OV12830=y
 CONFIG_OV5648=y
+CONFIG_IMX134=y
 CONFIG_MSM_CAMERA_SENSOR=y
 # CONFIG_MSM_CPP is not set
 CONFIG_MSM_EEPROM=y
@@ -411,3 +414,4 @@
 CONFIG_SENSORS_MMA8X5X=y
 CONFIG_LOGCAT_SIZE=64
 CONFIG_SENSORS_CAPELLA_CM36283=y
+CONFIG_NFC_QNCI=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 8238414..2c5363d 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -236,6 +236,8 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
@@ -285,6 +287,7 @@
 CONFIG_s5k4e1=y
 CONFIG_HI256=y
 CONFIG_OV12830=y
+CONFIG_IMX134=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CCI=y
@@ -442,6 +445,7 @@
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 1d645e2..c668cb2 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -240,18 +240,18 @@
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BT_RFCOMM_TTY is not set
+# CONFIG_BT_BNEP is not set
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
 CONFIG_BT_HIDP=y
-CONFIG_BT_HCISMD=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_ATH3K=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
+# CONFIG_BT_HCISMD is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_IBS is not set
+# CONFIG_MSM_BT_POWER is not set
 CONFIG_CFG80211=m
 CONFIG_CFG80211_INTERNAL_REGDB=y
 # CONFIG_CFG80211_WEXT is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a9e39ed..fb05a08 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -94,6 +94,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -168,6 +169,7 @@
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_HELPER=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
@@ -286,6 +288,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
@@ -336,6 +340,7 @@
 CONFIG_MT9M114=y
 CONFIG_OV2720=y
 CONFIG_IMX135=y
+CONFIG_IMX132=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index ee38cc8..b26a028 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -100,6 +100,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -174,6 +175,7 @@
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_HELPER=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
@@ -294,6 +296,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
@@ -318,6 +322,7 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_SMB350_CHARGER=y
+CONFIG_SMB349_USB_CHARGER=y
 CONFIG_BATTERY_BQ28400=y
 CONFIG_QPNP_CHARGER=y
 CONFIG_BATTERY_BCL=y
@@ -343,6 +348,7 @@
 CONFIG_MT9M114=y
 CONFIG_OV2720=y
 CONFIG_IMX135=y
+CONFIG_IMX132=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 38050b1..56211f2 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -130,4 +130,10 @@
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
+#ifdef CONFIG_MMU
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+int arch_setup_additional_pages(struct linux_binprm *, int);
+#endif
+
 #endif
diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h
index febe495..15cb035 100644
--- a/arch/arm/include/asm/mach/irq.h
+++ b/arch/arm/include/asm/mach/irq.h
@@ -17,7 +17,7 @@
 /*
  * This is internal.  Do not use it.
  */
-extern void init_FIQ(void);
+extern void init_FIQ(int);
 extern int show_fiq_list(struct seq_file *, int);
 
 #ifdef CONFIG_MULTI_IRQ_HANDLER
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index b8e580a..cf0c81f 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -9,6 +9,7 @@
 	raw_spinlock_t id_lock;
 #endif
 	unsigned int kvm_seq;
+	unsigned long	sigpage;
 } mm_context_t;
 
 #ifdef CONFIG_CPU_HAS_ASID
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index afc1ca7..673205e 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -151,7 +151,9 @@
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
 
+#ifdef CONFIG_KUSER_HELPERS
 #define __HAVE_ARCH_GATE_AREA 1
+#endif
 
 #ifdef CONFIG_ARM_LPAE
 #include <asm/pgtable-3level-types.h>
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 07209d7..3a2cd22 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -30,6 +30,7 @@
 #endif
 
 extern unsigned int boot_reason;
+extern unsigned int cold_boot;
 
 struct debug_info {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 67d6443..2eb0c2c 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -58,7 +58,7 @@
 	struct cpu_context_save	cpu_context;	/* cpu context */
 	__u32			syscall;	/* syscall number */
 	__u8			used_cp[16];	/* thread used copro */
-	unsigned long		tp_value;
+	unsigned long		tp_value[2];	/* TLS registers */
 	struct crunch_state	crunchstate;
 	union fp_state		fpstate __attribute__((aligned(8)));
 	union vfp_state		vfpstate;
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
index 73409e6..83259b8 100644
--- a/arch/arm/include/asm/tls.h
+++ b/arch/arm/include/asm/tls.h
@@ -2,27 +2,30 @@
 #define __ASMARM_TLS_H
 
 #ifdef __ASSEMBLY__
-	.macro set_tls_none, tp, tmp1, tmp2
+#include <asm/asm-offsets.h>
+	.macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
 	.endm
 
-	.macro set_tls_v6k, tp, tmp1, tmp2
+	.macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
+	mrc	p15, 0, \tmp2, c13, c0, 2	@ get the user r/w register
 	mcr	p15, 0, \tp, c13, c0, 3		@ set TLS register
-	mov	\tmp1, #0
-	mcr	p15, 0, \tmp1, c13, c0, 2	@ clear user r/w TLS register
+	mcr	p15, 0, \tpuser, c13, c0, 2	@ and the user r/w register
+	str	\tmp2, [\base, #TI_TP_VALUE + 4] @ save it
 	.endm
 
-	.macro set_tls_v6, tp, tmp1, tmp2
+	.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
 	ldr	\tmp1, =elf_hwcap
 	ldr	\tmp1, [\tmp1, #0]
 	mov	\tmp2, #0xffff0fff
 	tst	\tmp1, #HWCAP_TLS		@ hardware TLS available?
-	mcrne	p15, 0, \tp, c13, c0, 3		@ yes, set TLS register
-	movne	\tmp1, #0
-	mcrne	p15, 0, \tmp1, c13, c0, 2	@ clear user r/w TLS register
 	streq	\tp, [\tmp2, #-15]		@ set TLS value at 0xffff0ff0
+	mrcne	p15, 0, \tmp2, c13, c0, 2	@ get the user r/w register
+	mcrne	p15, 0, \tp, c13, c0, 3		@ yes, set TLS register
+	mcrne	p15, 0, \tpuser, c13, c0, 2	@ set user r/w register
+	strne	\tmp2, [\base, #TI_TP_VALUE + 4] @ save it
 	.endm
 
-	.macro set_tls_software, tp, tmp1, tmp2
+	.macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
 	mov	\tmp1, #0xffff0fff
 	str	\tp, [\tmp1, #-15]		@ set TLS value at 0xffff0ff0
 	.endm
@@ -31,19 +34,30 @@
 #ifdef CONFIG_TLS_REG_EMUL
 #define tls_emu		1
 #define has_tls_reg		1
-#define set_tls		set_tls_none
+#define switch_tls	switch_tls_none
 #elif defined(CONFIG_CPU_V6)
 #define tls_emu		0
 #define has_tls_reg		(elf_hwcap & HWCAP_TLS)
-#define set_tls		set_tls_v6
+#define switch_tls	switch_tls_v6
 #elif defined(CONFIG_CPU_32v6K)
 #define tls_emu		0
 #define has_tls_reg		1
-#define set_tls		set_tls_v6k
+#define switch_tls	switch_tls_v6k
 #else
 #define tls_emu		0
 #define has_tls_reg		0
-#define set_tls		set_tls_software
+#define switch_tls	switch_tls_software
 #endif
 
+#ifndef __ASSEMBLY__
+static inline unsigned long get_tpuser(void)
+{
+	unsigned long reg = 0;
+
+	if (has_tls_reg && !tls_emu)
+		__asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
+
+	return reg;
+}
+#endif
 #endif	/* __ASMARM_TLS_H */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 9f52940..317400a 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -698,15 +698,16 @@
  UNWIND(.fnstart	)
  UNWIND(.cantunwind	)
 	add	ip, r1, #TI_CPU_SAVE
-	ldr	r3, [r2, #TI_TP_VALUE]
  ARM(	stmia	ip!, {r4 - sl, fp, sp, lr} )	@ Store most regs on stack
  THUMB(	stmia	ip!, {r4 - sl, fp}	   )	@ Store most regs on stack
  THUMB(	str	sp, [ip], #4		   )
  THUMB(	str	lr, [ip], #4		   )
+	ldr	r4, [r2, #TI_TP_VALUE]
+	ldr	r5, [r2, #TI_TP_VALUE + 4]
 #ifdef CONFIG_CPU_USE_DOMAINS
 	ldr	r6, [r2, #TI_CPU_DOMAIN]
 #endif
-	set_tls	r3, r4, r5
+	switch_tls r1, r4, r5, r3, r7
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
 	ldr	r7, [r2, #TI_TASK]
 	ldr	r8, =__stack_chk_guard
@@ -754,6 +755,18 @@
 #endif
 	.endm
 
+	.macro	kuser_pad, sym, size
+	.if	(. - \sym) & 3
+	.rept	4 - (. - \sym) & 3
+	.byte	0
+	.endr
+	.endif
+	.rept	(\size - (. - \sym)) / 4
+	.word	0xe7fddef1
+	.endr
+	.endm
+
+#ifdef CONFIG_KUSER_HELPERS
 	.align	5
 	.globl	__kuser_helper_start
 __kuser_helper_start:
@@ -935,18 +948,13 @@
 #error "incoherent kernel configuration"
 #endif
 
-	/* pad to next slot */
-	.rept	(16 - (. - __kuser_cmpxchg64)/4)
-	.word	0
-	.endr
-
-	.align	5
+	kuser_pad __kuser_cmpxchg64, 64
 
 __kuser_memory_barrier:				@ 0xffff0fa0
 	smp_dmb	arm
 	usr_ret	lr
 
-	.align	5
+	kuser_pad __kuser_memory_barrier, 32
 
 __kuser_cmpxchg:				@ 0xffff0fc0
 
@@ -1019,13 +1027,14 @@
 
 #endif
 
-	.align	5
+	kuser_pad __kuser_cmpxchg, 32
 
 __kuser_get_tls:				@ 0xffff0fe0
 	ldr	r0, [pc, #(16 - 8)]	@ read TLS, set in kuser_get_tls_init
 	usr_ret	lr
 	mrc	p15, 0, r0, c13, c0, 3	@ 0xffff0fe8 hardware TLS code
-	.rep	4
+	kuser_pad __kuser_get_tls, 16
+	.rep	3
 	.word	0			@ 0xffff0ff0 software TLS value, then
 	.endr				@ pad up to __kuser_helper_version
 
@@ -1035,14 +1044,16 @@
 	.globl	__kuser_helper_end
 __kuser_helper_end:
 
+#endif
+
  THUMB(	.thumb	)
 
 /*
  * Vector stubs.
  *
- * This code is copied to 0xffff0200 so we can use branches in the
- * vectors, rather than ldr's.  Note that this code must not
- * exceed 0x300 bytes.
+ * This code is copied to 0xffff1000 so we can use branches in the
+ * vectors, rather than ldr's.  Note that this code must not exceed
+ * a page size.
  *
  * Common stub entry macro:
  *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
@@ -1101,8 +1112,17 @@
 1:
 	.endm
 
-	.globl	__stubs_start
+	.section .stubs, "ax", %progbits
 __stubs_start:
+	@ This must be the first word
+	.word	vector_swi
+
+vector_rst:
+ ARM(	swi	SYS_ERROR0	)
+ THUMB(	svc	#0		)
+ THUMB(	nop			)
+	b	vector_und
+
 /*
  * Interrupt dispatcher
  */
@@ -1197,6 +1217,16 @@
 	.align	5
 
 /*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit data mode).
+ */
+
+vector_addrexcptn:
+	b	vector_addrexcptn
+
+/*=============================================================================
  * Undefined FIQs
  *-----------------------------------------------------------------------------
  * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
@@ -1209,47 +1239,22 @@
 vector_fiq:
 	subs	pc, lr, #4
 
-/*=============================================================================
- * Address exception handler
- *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit data mode).
- */
-
-vector_addrexcptn:
-	b	vector_addrexcptn
-
-/*
- * We group all the following data together to optimise
- * for CPUs with separate I & D caches.
- */
-	.align	5
-
-.LCvswi:
-	.word	vector_swi
 .krait_fixup:
 	.word	msm_krait_need_wfe_fixup
 
-	.globl	__stubs_end
-__stubs_end:
+	.globl	vector_fiq_offset
+	.equ	vector_fiq_offset, vector_fiq
 
-	.equ	stubs_offset, __vectors_start + 0x200 - __stubs_start
-
-	.globl	__vectors_start
+	.section .vectors, "ax", %progbits
 __vectors_start:
- ARM(	swi	SYS_ERROR0	)
- THUMB(	svc	#0		)
- THUMB(	nop			)
-	W(b)	vector_und + stubs_offset
-	W(ldr)	pc, .LCvswi + stubs_offset
-	W(b)	vector_pabt + stubs_offset
-	W(b)	vector_dabt + stubs_offset
-	W(b)	vector_addrexcptn + stubs_offset
-	W(b)	vector_irq + stubs_offset
-	W(b)	vector_fiq + stubs_offset
-
-	.globl	__vectors_end
-__vectors_end:
+	W(b)	vector_rst
+	W(b)	vector_und
+	W(ldr)	pc, __vectors_start + 0x1000
+	W(b)	vector_pabt
+	W(b)	vector_dabt
+	W(b)	vector_addrexcptn
+	W(b)	vector_irq
+	W(b)	vector_fiq
 
 	.data
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index ca852c5..f9f16ef 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -48,6 +48,11 @@
 #include <asm/irq.h>
 #include <asm/traps.h>
 
+#define FIQ_OFFSET ({					\
+		extern void *vector_fiq_offset;		\
+		(unsigned)&vector_fiq_offset;		\
+	})
+
 static unsigned long no_fiq_insn;
 
 /* Default reacquire function
@@ -80,14 +85,14 @@
 
 void set_fiq_handler(void *start, unsigned int length)
 {
-#if defined(CONFIG_CPU_USE_DOMAINS)
-	memcpy((void *)0xffff001c, start, length);
-#else
-	memcpy(vectors_page + 0x1c, start, length);
-#endif
-	flush_icache_range(0xffff001c, 0xffff001c + length);
-	if (!vectors_high())
-		flush_icache_range(0x1c, 0x1c + length);
+	void *base = vectors_page;
+	unsigned offset = FIQ_OFFSET;
+
+	memcpy(base + offset, start, length);
+	if (!cache_is_vipt_nonaliasing())
+		flush_icache_range((unsigned long)base + offset, offset +
+				   length);
+	flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
 }
 
 int claim_fiq(struct fiq_handler *f)
@@ -123,14 +128,16 @@
 	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
 }
 
+static int fiq_start;
+
 void enable_fiq(int fiq)
 {
-	enable_irq(fiq + FIQ_START);
+	enable_irq(fiq + fiq_start);
 }
 
 void disable_fiq(int fiq)
 {
-	disable_irq(fiq + FIQ_START);
+	disable_irq(fiq + fiq_start);
 }
 
 void fiq_set_type(int fiq, unsigned int type)
@@ -147,7 +154,9 @@
 EXPORT_SYMBOL(disable_fiq);
 EXPORT_SYMBOL(fiq_set_type);
 
-void __init init_FIQ(void)
+void __init init_FIQ(int start)
 {
-	no_fiq_insn = *(unsigned long *)0xffff001c;
+	unsigned offset = FIQ_OFFSET;
+	no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
+	fiq_start = start;
 }
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 0241da1..2a3ab6e 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -116,7 +116,12 @@
 static int
 armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
 {
-	int mapping = (*event_map)[config];
+	int mapping;
+
+	if (config >= PERF_COUNT_HW_MAX)
+		return -EINVAL;
+
+	mapping = (*event_map)[config];
 	return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
 }
 
@@ -341,6 +346,9 @@
 	struct hw_perf_event fake_event = event->hw;
 	struct pmu *leader_pmu = event->group_leader->pmu;
 
+	if (is_software_event(event))
+		return 1;
+
 	if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
 		return 1;
 
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index fe97ff2..c5fa883 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -38,6 +38,7 @@
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/time.h>
+#include <asm/tls.h>
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
@@ -534,7 +535,8 @@
 	clear_ptrace_hw_breakpoint(p);
 
 	if (clone_flags & CLONE_SETTLS)
-		thread->tp_value = regs->ARM_r3;
+		thread->tp_value[0] = childregs->ARM_r3;
+	thread->tp_value[1] = get_tpuser();
 
 	thread_notify(THREAD_NOTIFY_COPY, thread);
 
@@ -650,10 +652,11 @@
 }
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_KUSER_HELPERS
 /*
  * The vectors page is always readable from user space for the
- * atomic helpers and the signal restart code. Insert it into the
- * gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
+ * atomic helpers. Insert it into the gate_vma so that it is visible
+ * through ptrace and /proc/<pid>/mem.
  */
 static struct vm_area_struct gate_vma;
 
@@ -682,14 +685,53 @@
 {
 	return in_gate_area(NULL, addr);
 }
+#define is_gate_vma(vma)	((vma) == &gate_vma)
+#else
+#define is_gate_vma(vma)	0
+#endif
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
-	if (vma == &gate_vma)
+	if (is_gate_vma(vma))
 		return "[vectors]";
+	else if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage)
+		return "[sigpage]";
 	else if (vma == get_user_timers_vma(NULL))
 		return "[timers]";
 	else
 		return NULL;
 }
+
+static struct page *signal_page;
+extern struct page *get_signal_page(void);
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr;
+	int ret;
+
+	if (!signal_page)
+		signal_page = get_signal_page();
+	if (!signal_page)
+		return -ENOMEM;
+
+	down_write(&mm->mmap_sem);
+	addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+	if (IS_ERR_VALUE(addr)) {
+		ret = addr;
+		goto up_fail;
+	}
+
+	ret = install_special_mapping(mm, addr, PAGE_SIZE,
+		VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+		&signal_page);
+
+	if (ret == 0)
+		mm->context.sigpage = addr;
+
+ up_fail:
+	up_write(&mm->mmap_sem);
+	return ret;
+}
 #endif
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 9650c14..c6c6be7 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -844,7 +844,7 @@
 #endif
 
 		case PTRACE_GET_THREAD_AREA:
-			ret = put_user(task_thread_info(child)->tp_value,
+			ret = put_user(task_thread_info(child)->tp_value[0],
 				       datap);
 			break;
 
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 28b114f..7298f9a 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -107,6 +107,9 @@
 unsigned int boot_reason;
 EXPORT_SYMBOL(boot_reason);
 
+unsigned int cold_boot;
+EXPORT_SYMBOL(cold_boot);
+
 #ifdef MULTI_CPU
 struct processor processor __read_mostly;
 #endif
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index d68d1b6..e000e5e 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/errno.h>
+#include <linux/random.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
 #include <linux/freezer.h>
@@ -16,10 +17,10 @@
 
 #include <asm/elf.h>
 #include <asm/cacheflush.h>
+#include <asm/traps.h>
 #include <asm/ucontext.h>
 #include <asm/unistd.h>
 #include <asm/vfp.h>
-
 #include "signal.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -44,7 +45,7 @@
 #define SWI_THUMB_SIGRETURN	(0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
 #define SWI_THUMB_RT_SIGRETURN	(0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
 
-const unsigned long sigreturn_codes[7] = {
+static const unsigned long sigreturn_codes[7] = {
 	MOV_R7_NR_SIGRETURN,    SWI_SYS_SIGRETURN,    SWI_THUMB_SIGRETURN,
 	MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
 };
@@ -112,6 +113,8 @@
 	return ret;
 }
 
+static unsigned long signal_return_offset;
+
 #ifdef CONFIG_CRUNCH
 static int preserve_crunch_context(struct crunch_sigframe __user *frame)
 {
@@ -460,13 +463,20 @@
 		    __put_user(sigreturn_codes[idx+1], rc+1))
 			return 1;
 
+#ifdef CONFIG_MMU
 		if (cpsr & MODE32_BIT) {
+			struct mm_struct *mm = current->mm;
+
 			/*
-			 * 32-bit code can use the new high-page
-			 * signal return code support.
+			 * 32-bit code can use the signal return page
+			 * except when the MPU has protected the vectors
+			 * page from PL0
 			 */
-			retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
-		} else {
+			retcode = mm->context.sigpage + signal_return_offset +
+				  (idx << 2) + thumb;
+		} else
+#endif
+		{
 			/*
 			 * Ensure that the instruction cache sees
 			 * the return code written onto the stack.
@@ -739,3 +749,33 @@
 			key_replace_session_keyring();
 	}
 }
+
+struct page *get_signal_page(void)
+{
+	unsigned long ptr;
+	unsigned offset;
+	struct page *page;
+	void *addr;
+
+	page = alloc_pages(GFP_KERNEL, 0);
+
+	if (!page)
+		return NULL;
+
+	addr = page_address(page);
+
+	/* Give the signal return code some randomness */
+	offset = 0x200 + (get_random_int() & 0x7fc);
+	signal_return_offset = offset;
+
+	/*
+	 * Copy signal return handlers into the vector page, and
+	 * set sigreturn to be a pointer to these.
+	 */
+	memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
+
+	ptr = (unsigned long)addr + offset;
+	flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
+
+	return page;
+}
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 6fcfe83..a0dcf5f 100644
--- a/arch/arm/kernel/signal.h
+++ b/arch/arm/kernel/signal.h
@@ -10,5 +10,4 @@
 #define KERN_SIGRETURN_CODE	(CONFIG_VECTORS_BASE + 0x00000500)
 #define KERN_RESTART_CODE	(KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
 
-extern const unsigned long sigreturn_codes[7];
 extern const unsigned long syscall_restart_code[2];
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 1e9504b..bd49b1f 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -35,8 +35,6 @@
 #include <asm/tls.h>
 #include <asm/system_misc.h>
 
-#include "signal.h"
-
 #include <trace/events/exception.h>
 
 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
@@ -566,7 +564,7 @@
 		return regs->ARM_r0;
 
 	case NR(set_tls):
-		thread->tp_value = regs->ARM_r0;
+		thread->tp_value[0] = regs->ARM_r0;
 		if (tls_emu)
 			return 0;
 		if (has_tls_reg) {
@@ -684,7 +682,7 @@
 	int reg = (instr >> 12) & 15;
 	if (reg == 15)
 		return 1;
-	regs->uregs[reg] = current_thread_info()->tp_value;
+	regs->uregs[reg] = current_thread_info()->tp_value[0];
 	regs->ARM_pc += 4;
 	return 0;
 }
@@ -785,49 +783,55 @@
 	return;
 }
 
-static void __init kuser_get_tls_init(unsigned long vectors)
+#ifdef CONFIG_KUSER_HELPERS
+static void __init kuser_init(void *vectors)
 {
+	extern char __kuser_helper_start[], __kuser_helper_end[];
+	int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+
+	memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+
 	/*
 	 * vectors + 0xfe0 = __kuser_get_tls
 	 * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
 	 */
 	if (tls_emu || has_tls_reg)
-		memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
+		memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
 }
+#else
+static void __init kuser_init(void *vectors)
+{
+}
+#endif
 
 void __init early_trap_init(void *vectors_base)
 {
 	unsigned long vectors = (unsigned long)vectors_base;
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
-	extern char __kuser_helper_start[], __kuser_helper_end[];
-	int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+	unsigned i;
 
 	vectors_page = vectors_base;
 
 	/*
+	 * Poison the vectors page with an undefined instruction.  This
+	 * instruction is chosen to be undefined for both ARM and Thumb
+	 * ISAs.  The Thumb version is an undefined instruction with a
+	 * branch back to the undefined instruction.
+	 */
+	for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
+		((u32 *)vectors_base)[i] = 0xe7fddef1;
+
+	/*
 	 * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
 	 * into the vector page, mapped at 0xffff0000, and ensure these
 	 * are visible to the instruction stream.
 	 */
 	memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-	memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
-	memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+	memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
 
-	/*
-	 * Do processor specific fixups for the kuser helpers
-	 */
-	kuser_get_tls_init(vectors);
+	kuser_init(vectors_base);
 
-	/*
-	 * Copy signal return handlers into the vector page, and
-	 * set sigreturn to be a pointer to these.
-	 */
-	memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
-	       sigreturn_codes, sizeof(sigreturn_codes));
-	memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
-	       syscall_restart_code, sizeof(syscall_restart_code));
-
-	flush_icache_range(vectors, vectors + PAGE_SIZE);
+	flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
 	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 }
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 0bf55ae..68c312b 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -151,6 +151,23 @@
 #endif
 	__init_begin = .;
 #endif
+	/*
+	 * The vectors and stubs are relocatable code, and the
+	 * only thing that matters is their relative offsets
+	 */
+	__vectors_start = .;
+	.vectors 0 : AT(__vectors_start) {
+		*(.vectors)
+	}
+	. = __vectors_start + SIZEOF(.vectors);
+	__vectors_end = .;
+
+	__stubs_start = .;
+	.stubs 0x1000 : AT(__stubs_start) {
+		*(.stubs)
+	}
+	. = __stubs_start + SIZEOF(.stubs);
+	__stubs_end = .;
 
 	INIT_TEXT_SECTION(8)
 	.exit.text : {
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87e3e5b..87c2f8c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -473,6 +473,7 @@
 	select MSM_JTAG_MM if CORESIGHT_ETM
 	select MSM_CPR_REGULATOR
 	select MSM_RPM_LOG
+	select MSM_IOMMU_SYNC
 	select MSM_RPM_STATS_LOG
 
 config ARCH_MSM8226
@@ -1761,6 +1762,16 @@
 	help
 	  SMD Transport Layer for IPC Router
 
+config MSM_IPC_ROUTER_HSIC_XPRT
+	depends on USB_QCOM_IPC_BRIDGE
+	depends on MSM_IPC_ROUTER
+	bool "MSM HSIC XPRT Layer"
+	help
+	  HSIC Transport Layer that enables off-chip communication of
+	  IPC Router. When the HSIC endpoint becomes available, this layer
+	  registers the transport with IPC Router and enable message
+	  exchange.
+
 config MSM_IPC_ROUTER_SECURITY
 	depends on MSM_IPC_ROUTER
 	bool "MSM IPC Router Security support"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 89eb589..dd533f4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -130,6 +130,7 @@
 obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
 obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
 obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
+obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
 obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 910264e..552ed16 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -67,11 +67,14 @@
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2.2-fluid.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2.2-liquid.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2.2-mtp.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-fluid.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-liquid.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-mtp.dtb
-        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ac-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-fluid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-liquid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ac-pm8941-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ac-pm8941-liquid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ac-pm8941-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ac-pma8084-pm8941-mtp.dtb
 
 # APQ8084
    zreladdr-$(CONFIG_ARCH_APQ8084)	:= 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 9ea00c1..da3cfba 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -49,7 +49,7 @@
 	[2] =  BW_MBPS(400), /* At least 50 MHz on bus. */
 	[3] =  BW_MBPS(800), /* At least 100 MHz on bus. */
 	[4] = BW_MBPS(1600), /* At least 200 MHz on bus. */
-	[5] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+	[5] = BW_MBPS(2664), /* At least 333 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_client_pdata = {
@@ -63,7 +63,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -74,7 +74,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -85,7 +85,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -95,26 +95,11 @@
 	{ 0 }
 };
 
-static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p5[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 0 }
-};
-
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -141,8 +126,8 @@
 	[6] = acpu_freq_tbl_8226_1p2,
 	[2] = acpu_freq_tbl_8226_1p4,
 	[5] = acpu_freq_tbl_8226_1p4,
-	[4] = acpu_freq_tbl_8226_1p5,
-	[7] = acpu_freq_tbl_8226_1p5,
+	[4] = acpu_freq_tbl_8226_1p4,
+	[7] = acpu_freq_tbl_8226_1p4,
 	[1] = acpu_freq_tbl_8226_1p6,
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 6d848d2..66534eb 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -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 },
@@ -899,120 +899,1664 @@
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_pro_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000, 999 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 999 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 999 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 999 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 999 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 999 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 999 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 999 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 999 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 999 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 999 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 999 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 999 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 999 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 999 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 999 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 999 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 999 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 999 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 999 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 999 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 999 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 999 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 999 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 999 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 999 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 999 },
-	/* higher frequencies aren't available for bring up */
+static struct acpu_level pro_rev0_2p3g_pvs0[] __initdata = {
+	{ 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 pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* 8974v1 1.7GHz Parts */
-	[0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
-	[0][1] = { acpu_freq_tbl_v1_pvs1, sizeof(acpu_freq_tbl_v1_pvs1) },
-	[0][2] = { acpu_freq_tbl_v1_pvs2, sizeof(acpu_freq_tbl_v1_pvs2) },
-	[0][3] = { acpu_freq_tbl_v1_pvs3, sizeof(acpu_freq_tbl_v1_pvs3) },
-	[0][4] = { acpu_freq_tbl_v1_pvs4, sizeof(acpu_freq_tbl_v1_pvs4) },
+static struct acpu_level pro_rev0_2p3g_pvs1[] __initdata = {
+	{ 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 pvs_table pvs_v2[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+static struct acpu_level pro_rev0_2p3g_pvs2[] __initdata = {
+	{ 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,  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,  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,  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,  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 } }
+};
+
+static struct acpu_level pro_rev0_2p5g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 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),  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 } }
+};
+
+static struct acpu_level pro_rev0_2p5g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 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, 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 } }
+};
+
+static struct acpu_level pro_rev0_2p5g_pvs2[] __initdata = {
+	{ 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),  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 } }
+};
+
+static struct acpu_level pro_rev0_2p5g_pvs3[] __initdata = {
+	{ 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),  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),  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 } }
+};
+
+static struct acpu_level pro_rev0_2p5g_pvs5[] __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, 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),  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 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  810000, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  820000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  830000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  840000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  850000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  860000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  870000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  920000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  930000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  940000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  950000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  965000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  980000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  995000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1010000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1115000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1120000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  870000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  880000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  890000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  900000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  920000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1105000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1110000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  910000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  920000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  930000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  945000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  960000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  975000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  990000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1095000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1100000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  860000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  870000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  880000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  900000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1085000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1090000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  880000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  890000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  900000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  910000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  925000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  940000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  955000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  970000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1075000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1080000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  870000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  880000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  890000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  960000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1065000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1070000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs6[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  870000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  890000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  905000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  920000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  935000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  950000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1060000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs7[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  880000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  895000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  940000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1045000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1050000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs8[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  780000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  790000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  810000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  820000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  830000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  840000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  850000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  915000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1035000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1040000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs9[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  780000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  790000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  800000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  810000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  820000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  830000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  840000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  850000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  860000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  875000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  890000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  920000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1025000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1030000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs10[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  830000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  850000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  880000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  910000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1015000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1020000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs11[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  820000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  840000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  855000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  870000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  900000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1010000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs12[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  775000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  845000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  875000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  890000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  995000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19), 1000000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs13[] __initdata = {
+	{ 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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  775000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  775000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  800000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  810000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  820000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  835000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  850000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  865000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  985000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19),  990000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs14[] __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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  750000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  760000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  770000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  780000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  790000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  800000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  810000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  825000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  840000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  855000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  870000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  975000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19),  980000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p5g_pvs15[] __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, 126 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 147 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 168 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 189 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 211 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 233 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 256 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 278 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  750000, 301 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  750000, 324 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  760000, 348 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  770000, 372 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  780000, 396 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  790000, 421 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  800000, 446 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  815000, 473 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  830000, 501 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  845000, 529 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  860000, 558 },
+	{ 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 },
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  965000, 786 },
+	{ 1, { 2457600, HFPLL, 1, 128 }, L2(19),  970000, 802 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  810000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  820000, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  830000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  840000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  850000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  860000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  870000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  880000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  890000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  900000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  910000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  920000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  930000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  940000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  955000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  970000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  985000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17), 1000000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1015000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1030000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1045000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  810000, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  820000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  830000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  840000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  850000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  860000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  870000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  880000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  900000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  910000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  920000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  930000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  945000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  960000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  975000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  990000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18), 1005000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1020000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1035000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  810000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  820000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  830000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  840000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  850000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  860000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  870000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  880000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  910000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  920000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  935000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  810000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  820000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  830000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  840000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  850000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  860000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  870000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  880000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  890000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  900000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  910000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  925000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  940000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  955000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  970000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  985000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1000000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1015000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  810000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  820000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  830000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  840000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  850000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  870000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  880000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  945000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  960000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  975000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  990000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1005000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  860000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  870000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  880000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  890000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  905000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  920000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  935000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  950000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  965000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  980000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  995000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs6[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  780000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  790000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  810000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  820000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  830000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  880000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  925000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  940000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  955000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  970000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  985000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs7[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  780000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  790000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  810000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  820000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  840000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  850000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  860000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  870000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  885000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  900000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  915000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  930000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  945000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  960000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  975000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs8[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  860000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  890000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  905000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  920000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  935000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  950000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  965000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs9[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  780000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  790000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  820000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  830000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  840000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  865000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  895000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  910000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  925000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  940000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs10[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  780000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  790000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  810000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  820000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  830000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  840000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  855000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  915000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  945000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs11[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  780000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  790000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  800000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  810000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  820000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  830000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  875000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  890000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  905000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  920000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs12[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  850000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  865000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  880000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  910000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  925000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs13[] __initdata = {
+	{ 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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  870000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  885000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  900000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs14[] __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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  760000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  770000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  815000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  860000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  890000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  905000, 572 },
+	{ 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 } }
+};
+
+static struct acpu_level pro_rev1_2p3g_pvs15[] __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, 108 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 129 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 150 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 171 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 193 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 215 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 237 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 260 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 282 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  760000, 306 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  770000, 330 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 354 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 378 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  805000, 404 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 431 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  835000, 458 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 486 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  865000, 515 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  880000, 543 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 572 },
+	{ 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 } }
+};
+
+static struct pvs_table pvs_v1[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
+	/* 8974v1 1.7GHz Parts */
+	[0][0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
+	[0][0][1] = { acpu_freq_tbl_v1_pvs1, sizeof(acpu_freq_tbl_v1_pvs1) },
+	[0][0][2] = { acpu_freq_tbl_v1_pvs2, sizeof(acpu_freq_tbl_v1_pvs2) },
+	[0][0][3] = { acpu_freq_tbl_v1_pvs3, sizeof(acpu_freq_tbl_v1_pvs3) },
+	[0][0][4] = { acpu_freq_tbl_v1_pvs4, sizeof(acpu_freq_tbl_v1_pvs4) },
+};
+
+static struct pvs_table pvs_v2[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v2 2.0GHz Parts */
-	[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
-	[0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
-	[0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
-	[0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
-	[0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
-	[0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
-	[0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
 	/* 8974v2 2.3GHz Parts */
-	[1][0] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][1] = { acpu_freq_tbl_2p3g_pvs1, sizeof(acpu_freq_tbl_2p3g_pvs1) },
-	[1][2] = { acpu_freq_tbl_2p3g_pvs2, sizeof(acpu_freq_tbl_2p3g_pvs2) },
-	[1][3] = { acpu_freq_tbl_2p3g_pvs3, sizeof(acpu_freq_tbl_2p3g_pvs3) },
-	[1][4] = { acpu_freq_tbl_2p3g_pvs4, sizeof(acpu_freq_tbl_2p3g_pvs4) },
-	[1][5] = { acpu_freq_tbl_2p3g_pvs5, sizeof(acpu_freq_tbl_2p3g_pvs5) },
-	[1][6] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
-	[1][7] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
+	[0][1][0] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
+	[0][1][1] = { acpu_freq_tbl_2p3g_pvs1, sizeof(acpu_freq_tbl_2p3g_pvs1) },
+	[0][1][2] = { acpu_freq_tbl_2p3g_pvs2, sizeof(acpu_freq_tbl_2p3g_pvs2) },
+	[0][1][3] = { acpu_freq_tbl_2p3g_pvs3, sizeof(acpu_freq_tbl_2p3g_pvs3) },
+	[0][1][4] = { acpu_freq_tbl_2p3g_pvs4, sizeof(acpu_freq_tbl_2p3g_pvs4) },
+	[0][1][5] = { acpu_freq_tbl_2p3g_pvs5, sizeof(acpu_freq_tbl_2p3g_pvs5) },
+	[0][1][6] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
+	[0][1][7] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
 
 	/* 8974v2 2.2GHz Parts */
-	[2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
-	[2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
-	[2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
-	[2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
-	[2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
-	[2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
-	[2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
-	[2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[0][2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
+	[0][2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
+	[0][2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
+	[0][2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
+	[0][2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
+	[0][2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
+	[0][2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[0][2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
 };
 
-static struct pvs_table pvs_pro[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* Not used by 8974Pro */
-	[0][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+static struct pvs_table pvs_pro[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
+	/* 2.0 GHz is not used on 8974Pro */
+	[0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
-	/* 8974Pro AB Bringup */
-	[1][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AB 2.3GHz */
+	[0][1][0] = { pro_rev0_2p3g_pvs0, sizeof(pro_rev0_2p3g_pvs0) },
+	[0][1][1] = { pro_rev0_2p3g_pvs1, sizeof(pro_rev0_2p3g_pvs1) },
+	[0][1][2] = { pro_rev0_2p3g_pvs2, sizeof(pro_rev0_2p3g_pvs2) },
+	[0][1][3] = { pro_rev0_2p3g_pvs3, sizeof(pro_rev0_2p3g_pvs3) },
+	[0][1][4] = { pro_rev0_2p3g_pvs4, sizeof(pro_rev0_2p3g_pvs4) },
+	[0][1][5] = { pro_rev0_2p3g_pvs5, sizeof(pro_rev0_2p3g_pvs5) },
+	[0][1][6] = { pro_rev0_2p3g_pvs6, sizeof(pro_rev0_2p3g_pvs6) },
+	[0][1][7] = { pro_rev0_2p3g_pvs6, sizeof(pro_rev0_2p3g_pvs6) },
 
-	/* Not used by 8974Pro */
-	[2][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.2GHz is not used on 8974Pro */
+	[0][2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
+	[0][2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
+	[0][2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
+	[0][2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
+	[0][2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
+	[0][2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
+	[0][2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[0][2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
 
-	/* 8974Pro Bringup */
-	[3][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AC 2.5GHz */
+	[0][3][0] = { pro_rev0_2p5g_pvs0, sizeof(pro_rev0_2p5g_pvs0) },
+	[0][3][1] = { pro_rev0_2p5g_pvs1, sizeof(pro_rev0_2p5g_pvs1) },
+	[0][3][2] = { pro_rev0_2p5g_pvs2, sizeof(pro_rev0_2p5g_pvs2) },
+	[0][3][3] = { pro_rev0_2p5g_pvs3, sizeof(pro_rev0_2p5g_pvs3) },
+	[0][3][4] = { pro_rev0_2p5g_pvs4, sizeof(pro_rev0_2p5g_pvs4) },
+	[0][3][5] = { pro_rev0_2p5g_pvs5, sizeof(pro_rev0_2p5g_pvs5) },
+	[0][3][6] = { pro_rev0_2p5g_pvs6, sizeof(pro_rev0_2p5g_pvs6) },
+	[0][3][7] = { pro_rev0_2p5g_pvs6, sizeof(pro_rev0_2p5g_pvs6) },
+
+	/* 8974Pro AB 2.3GHz */
+	[1][1][0] = { pro_rev1_2p3g_pvs0, sizeof(pro_rev1_2p3g_pvs0) },
+	[1][1][1] = { pro_rev1_2p3g_pvs1, sizeof(pro_rev1_2p3g_pvs1) },
+	[1][1][2] = { pro_rev1_2p3g_pvs2, sizeof(pro_rev1_2p3g_pvs2) },
+	[1][1][3] = { pro_rev1_2p3g_pvs3, sizeof(pro_rev1_2p3g_pvs3) },
+	[1][1][4] = { pro_rev1_2p3g_pvs4, sizeof(pro_rev1_2p3g_pvs4) },
+	[1][1][5] = { pro_rev1_2p3g_pvs5, sizeof(pro_rev1_2p3g_pvs5) },
+	[1][1][6] = { pro_rev1_2p3g_pvs6, sizeof(pro_rev1_2p3g_pvs6) },
+	[1][1][7] = { pro_rev1_2p3g_pvs7, sizeof(pro_rev1_2p3g_pvs7) },
+	[1][1][8] = { pro_rev1_2p3g_pvs8, sizeof(pro_rev1_2p3g_pvs8) },
+	[1][1][9] = { pro_rev1_2p3g_pvs9, sizeof(pro_rev1_2p3g_pvs9) },
+	[1][1][10] = { pro_rev1_2p3g_pvs10, sizeof(pro_rev1_2p3g_pvs10) },
+	[1][1][11] = { pro_rev1_2p3g_pvs11, sizeof(pro_rev1_2p3g_pvs11) },
+	[1][1][12] = { pro_rev1_2p3g_pvs12, sizeof(pro_rev1_2p3g_pvs12) },
+	[1][1][13] = { pro_rev1_2p3g_pvs13, sizeof(pro_rev1_2p3g_pvs13) },
+	[1][1][14] = { pro_rev1_2p3g_pvs14, sizeof(pro_rev1_2p3g_pvs14) },
+	[1][1][15] = { pro_rev1_2p3g_pvs15, sizeof(pro_rev1_2p3g_pvs15) },
+
+	/* 8974Pro AC 2.5GHz */
+	[1][3][0] = { pro_rev1_2p5g_pvs0, sizeof(pro_rev1_2p5g_pvs0) },
+	[1][3][1] = { pro_rev1_2p5g_pvs1, sizeof(pro_rev1_2p5g_pvs1) },
+	[1][3][2] = { pro_rev1_2p5g_pvs2, sizeof(pro_rev1_2p5g_pvs2) },
+	[1][3][3] = { pro_rev1_2p5g_pvs3, sizeof(pro_rev1_2p5g_pvs3) },
+	[1][3][4] = { pro_rev1_2p5g_pvs4, sizeof(pro_rev1_2p5g_pvs4) },
+	[1][3][5] = { pro_rev1_2p5g_pvs5, sizeof(pro_rev1_2p5g_pvs5) },
+	[1][3][6] = { pro_rev1_2p5g_pvs6, sizeof(pro_rev1_2p5g_pvs6) },
+	[1][3][7] = { pro_rev1_2p5g_pvs7, sizeof(pro_rev1_2p5g_pvs7) },
+	[1][3][8] = { pro_rev1_2p5g_pvs8, sizeof(pro_rev1_2p5g_pvs8) },
+	[1][3][9] = { pro_rev1_2p5g_pvs9, sizeof(pro_rev1_2p5g_pvs9) },
+	[1][3][10] = { pro_rev1_2p5g_pvs10, sizeof(pro_rev1_2p5g_pvs10) },
+	[1][3][11] = { pro_rev1_2p5g_pvs11, sizeof(pro_rev1_2p5g_pvs11) },
+	[1][3][12] = { pro_rev1_2p5g_pvs12, sizeof(pro_rev1_2p5g_pvs12) },
+	[1][3][13] = { pro_rev1_2p5g_pvs13, sizeof(pro_rev1_2p5g_pvs13) },
+	[1][3][14] = { pro_rev1_2p5g_pvs14, sizeof(pro_rev1_2p5g_pvs14) },
+	[1][3][15] = { pro_rev1_2p5g_pvs15, sizeof(pro_rev1_2p5g_pvs15) },
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
@@ -1048,12 +2592,15 @@
 		{ }
 	};
 	struct acpu_level *l;
-	int s, p;
+	int s, p, r;
 
-	for (s = 0; s < NUM_SPEED_BINS; s++)
-		for (p = 0; p < NUM_PVS; p++)
-			for (l = pvs_v1[s][p].table; l && l->speed.khz; l++)
-				l->l2_level = l->l2_level > 5 ? 1 : 0;
+	for (r = 0; r < NUM_PVS_REVS; r++)
+		for (s = 0; s < NUM_SPEED_BINS; s++)
+			for (p = 0; p < NUM_PVS; p++) {
+				l = pvs_v1[r][s][p].table;
+				for (; l && l->speed.khz; l++)
+					l->l2_level = l->l2_level > 5 ? 1 : 0;
+			}
 
 	acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
 	acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index db66d27..cf3fac0 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -55,8 +55,12 @@
 	return drv.scalable[cpu].cur_speed->khz;
 }
 
-/* Select a source on the primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+struct set_clk_src_args {
+	struct scalable *sc;
+	u32 src_sel;
+};
+
+static void __set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
 {
 	u32 regval;
 
@@ -73,6 +77,27 @@
 	udelay(1);
 }
 
+static void __set_cpu_pri_clk_src(void *data)
+{
+	struct set_clk_src_args *args = data;
+	__set_pri_clk_src(args->sc, args->src_sel);
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+	int cpu = sc - drv.scalable;
+	if (sc != &drv.scalable[L2] && cpu_online(cpu)) {
+		struct set_clk_src_args args = {
+			.sc = sc,
+			.src_sel = pri_src_sel,
+		};
+		smp_call_function_single(cpu, __set_cpu_pri_clk_src, &args, 1);
+	} else {
+		__set_pri_clk_src(sc, pri_src_sel);
+	}
+}
+
 /* Select a source on the secondary MUX. */
 static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
 {
@@ -1067,15 +1092,17 @@
 
 	pte_efuse = readl_relaxed(base);
 	redundant_sel = (pte_efuse >> 24) & 0x7;
+	bin->pvs_rev = (pte_efuse >> 4) & 0x3;
 	bin->speed = pte_efuse & 0x7;
-	bin->pvs = (pte_efuse >> 6) & 0x7;
+	/* PVS number is in bits 31, 8, 7, 6 */
+	bin->pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
 
 	switch (redundant_sel) {
 	case 1:
-		bin->speed = (pte_efuse >> 27) & 0x7;
+		bin->speed = (pte_efuse >> 27) & 0xF;
 		break;
 	case 2:
-		bin->pvs = (pte_efuse >> 27) & 0x7;
+		bin->pvs = (pte_efuse >> 27) & 0xF;
 		break;
 	}
 	bin->speed_valid = true;
@@ -1111,13 +1138,15 @@
 	if (bin.pvs_valid) {
 		drv.pvs_bin = bin.pvs;
 		dev_info(drv.dev, "ACPU PVS: %d\n", drv.pvs_bin);
+		drv.pvs_rev = bin.pvs_rev;
+		dev_info(drv.dev, "ACPU PVS REVISION: %d\n", drv.pvs_rev);
 	} else {
 		drv.pvs_bin = 0;
 		dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n",
 			 drv.pvs_bin);
 	}
 
-	return &params->pvs_tables[drv.speed_bin][drv.pvs_bin];
+	return &params->pvs_tables[drv.pvs_rev][drv.speed_bin][drv.pvs_bin];
 }
 
 static void __init drv_data_init(struct device *dev,
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index f02af98..4eff45d 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -50,10 +50,15 @@
 	PVS_NOMINAL = 1,
 	PVS_FAST = 3,
 	PVS_FASTER = 4,
-	NUM_PVS = 8
+	NUM_PVS = 16
 };
 
 /**
+ * The maximum number of PVS revisions.
+ */
+#define NUM_PVS_REVS (4)
+
+/**
  * The maximum number of speed bins.
  */
 #define NUM_SPEED_BINS (16)
@@ -236,12 +241,14 @@
  * @pvs_valid: @pvs field is valid
  * @speed: Speed bin ID
  * @pvs: PVS bin ID
+ * @pvs_rev: PVS revision ID
  */
 struct bin_info {
 	bool speed_valid;
 	bool pvs_valid;
 	int speed;
 	int pvs;
+	int pvs_rev;
 };
 
 /**
@@ -273,7 +280,7 @@
 	struct scalable *scalable;
 	size_t scalable_size;
 	struct hfpll_data *hfpll_data;
-	struct pvs_table (*pvs_tables)[NUM_PVS];
+	struct pvs_table (*pvs_tables)[NUM_SPEED_BINS][NUM_PVS];
 	struct l2_level *l2_freq_tbl;
 	size_t l2_freq_tbl_size;
 	phys_addr_t pte_efuse_phys;
@@ -293,6 +300,7 @@
  * @boost_uv: Voltage boost amount
  * @speed_bin: Speed bin ID.
  * @pvs_bin: PVS bin ID.
+ * @pvs_bin: PVS revision ID.
  * @dev: Device.
  */
 struct drv_data {
@@ -305,6 +313,7 @@
 	int boost_uv;
 	int speed_bin;
 	int pvs_bin;
+	int pvs_rev;
 	struct device *dev;
 };
 
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 5dd9bab..4dcbc3a 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -18,6 +18,38 @@
 #include <mach/gpiomux.h>
 #include <mach/socinfo.h>
 
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct gpiomux_setting hsic_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_hsic_configs[] = {
+	{
+		.gpio = 115,               /* HSIC_STROBE */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+	{
+		.gpio = 116,               /* HSIC_DATA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+};
+#endif
+
 #define KS8851_IRQ_GPIO 115
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
@@ -824,4 +856,17 @@
 					ARRAY_SIZE(usb_otg_sw_configs));
 
 	msm_gpiomux_sdc3_install();
+
+	/*
+	 * HSIC STROBE gpio is also used by the ethernet. Install HSIC
+	 * gpio mux config only when HSIC is enabled. HSIC config will
+	 * be disabled when ethernet config is enabled.
+	 */
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+	if (machine_is_msm8926()) {
+		msm_hsic_configs[0].gpio = 119; /* STROBE */
+		msm_hsic_configs[1].gpio = 120; /* DATA */
+	}
+	msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
+#endif
 }
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index e9ad86f..b5ea3a5 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,6 +23,11 @@
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
@@ -36,6 +41,17 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_nfc_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+static struct gpiomux_setting gpio_nfc_sus_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting atmel_int_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -227,6 +243,13 @@
 			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
 		},
 	},
+	{
+		.gpio      = 78,	/* NFC CLK */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_nfc_config,
+			[GPIOMUX_SUSPENDED] = &gpio_nfc_sus_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
@@ -247,25 +270,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -288,25 +315,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -544,13 +575,6 @@
 		},
 	},
 	{
-		.gpio = 78,	/*ETH_INT */
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
-			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
-		},
-	},
-	{
 		.gpio = 80,	/*ALSP_INT */
 		.settings = {
 			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index f170b7b..c35a607 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -143,6 +143,11 @@
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_spi_cs1_config = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -223,6 +228,17 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_i2c_act_config = {
+	.func = GPIOMUX_FUNC_3,
+	/*
+	 * Please keep I2C GPIOs drive-strength at minimum (2ma). It is a
+	 * workaround for HW issue of glitches caused by rapid GPIO current-
+	 * change.
+	 */
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 static struct gpiomux_setting lcd_en_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -553,31 +569,36 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 9,		/* BLSP1 QUP SPI_CS2A_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs2_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 8,		/* BLSP1 QUP SPI_CS1_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs1_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs1_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 #endif
@@ -585,12 +606,14 @@
 		.gpio      = 6,		/* BLSP1 QUP2 I2C_DAT */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
 		.gpio      = 7,		/* BLSP1 QUP2 I2C_CLK */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1999379..993ce58 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -238,12 +238,6 @@
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a1_pin, cxo_a1_a_pin, A1_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a2_pin, cxo_a2_a_pin, A2_ID);
 
-struct measure_mux_entry {
-	struct clk *c;
-	int base;
-	u32 debug_mux;
-};
-
 static struct branch_clk oxilicx_axi_clk;
 
 #define MSS_DEBUG_CLOCK_CTL  0x0078
@@ -328,6 +322,7 @@
 #define CAMSS_VFE_VFE_AXI_CBCR                             (0x36BC)
 #define CAMSS_CSI_VFE0_BCR                                 (0x3700)
 #define CAMSS_CSI_VFE0_CBCR                                (0x3704)
+#define CAMSS_MICRO_BCR                                    (0x3490)
 #define OXILI_GFX3D_CBCR                                   (0x4028)
 #define OXILICX_BCR                                        (0x4030)
 #define OXILICX_AXI_CBCR                                   (0x4038)
@@ -1558,6 +1553,13 @@
 	},
 };
 
+#ifdef CONFIG_DEBUG_FS
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
 static struct measure_mux_entry measure_mux_GCC[] = {
 	{ &gcc_mss_cfg_ahb_clk.c,  GCC_BASE, 0x0030 },
 	{ &gcc_mss_q6_bimc_axi_clk.c,  GCC_BASE, 0x0031 },
@@ -1613,6 +1615,7 @@
 	{ &bimc_clk.c, GCC_BASE, 0x155},
 	{ &dummy_clk, N_BASES, 0x0000},
 };
+#endif /* CONFIG_DEBUG_FS */
 
 static struct pll_vote_clk mmpll0_pll = {
 	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS,
@@ -2365,6 +2368,7 @@
 static struct branch_clk camss_micro_ahb_clk = {
 	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
 	.has_sibling = 1,
+	.bcr_reg = CAMSS_MICRO_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_micro_ahb_clk",
@@ -2684,6 +2688,7 @@
 	},
 };
 
+#ifdef CONFIG_DEBUG_FS
 static struct measure_mux_entry measure_mux_MMSS[] = {
 	{ &mmss_mmssnoc_bto_ahb_clk.c,  MMSS_BASE, 0x0002 },
 	{ &mmss_misc_ahb_clk.c,  MMSS_BASE, 0x0003 },
@@ -2736,6 +2741,7 @@
 	{ &mmssnoc_ahb_clk.c,  MMSS_BASE, 0x0001 },
 	{&dummy_clk, N_BASES, 0x0000},
 };
+#endif /* CONFIG_DEBUG_FS */
 
 static struct branch_clk q6ss_ahb_lfabif_clk = {
 	.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
@@ -2771,12 +2777,14 @@
 	},
 };
 
+#ifdef CONFIG_DEBUG_FS
 static struct measure_mux_entry measure_mux_LPASS[] = {
 	{ &q6ss_ahbm_clk.c,  LPASS_BASE, 0x001d },
 	{ &q6ss_ahb_lfabif_clk.c,  LPASS_BASE, 0x001e },
 	{ &q6ss_xo_clk.c,  LPASS_BASE, 0x002b },
 	{&dummy_clk, N_BASES, 0x0000},
 };
+#endif /* CONFIG_DEBUG_FS */
 
 
 static DEFINE_CLK_MEASURE(apc0_m_clk);
@@ -2785,6 +2793,7 @@
 static DEFINE_CLK_MEASURE(apc3_m_clk);
 static DEFINE_CLK_MEASURE(l2_m_clk);
 
+#ifdef CONFIG_DEBUG_FS
 static struct  measure_mux_entry measure_mux_APSS[] = {
 	{&apc0_m_clk,                    APCS_BASE, 0x00010},
 	{&apc1_m_clk,                    APCS_BASE, 0x00114},
@@ -2793,6 +2802,7 @@
 	{&l2_m_clk,                      APCS_BASE, 0x01000},
 	{&dummy_clk, N_BASES, 0x0000}
 };
+#endif /* CONFIG_DEBUG_FS */
 
 #define APCS_SH_PLL_MODE        (0x000)
 #define APCS_SH_PLL_L_VAL       (0x004)
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 33dcd9f..85a9f45 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2923,7 +2923,7 @@
 	CLK_LOOKUP("core_clk",                  gcc_ce1_clk.c, ""),
 	CLK_LOOKUP("iface_clk",       gcc_copss_smmu_ahb_clk.c, ""),
 	CLK_LOOKUP("iface_clk",        gcc_lpss_smmu_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk",                  gcc_gp1_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  gcc_gp1_clk.c, "0-000e"),
 	CLK_LOOKUP("core_clk",                  gcc_gp2_clk.c, ""),
 	CLK_LOOKUP("core_clk",                  gcc_gp3_clk.c, ""),
 	CLK_LOOKUP("core_clk",         gcc_lpass_q6_axi_clk.c, ""),
@@ -3022,12 +3022,14 @@
 
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006f"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0034"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-007d"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006a"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0034"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
 	CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 654dbd3..b0adfa0 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -777,7 +777,7 @@
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.parent = &cxo_clk_src.c,
-		.rate = 800000000,
+		.rate = 768000000,
 		.dbg_name = "gpll4_clk_src",
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(gpll4_clk_src.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(400000000,  gpll4,   2,   0,   0),
 	F_END
 };
 
@@ -3909,6 +3926,7 @@
 static struct branch_clk camss_micro_ahb_clk = {
 	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
 	.has_sibling = 1,
+	.bcr_reg = CAMSS_MICRO_BCR,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "camss_micro_ahb_clk",
@@ -5208,26 +5226,56 @@
 
 	/* ISPIF clocks */
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
 
-	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, "fda0a000.qcom,ispif"),
+	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c,
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c,
-			   "fda0a000.qcom,ispif"),
-	CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c,
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
+
 	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c,
-			   "fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
+
+	CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_clk", camss_csi1_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c,
+					"fda0a000.qcom,ispif"),
+
+	CLK_LOOKUP("csi2_src_clk", csi2_clk_src.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi2_clk", camss_csi2_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi2_pix_clk", camss_csi2pix_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi2_rdi_clk", camss_csi2rdi_clk.c,
+					"fda0a000.qcom,ispif"),
+
+	CLK_LOOKUP("csi3_src_clk", csi3_clk_src.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi3_clk", camss_csi3_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi3_pix_clk", camss_csi3pix_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi3_rdi_clk", camss_csi3rdi_clk.c,
+					"fda0a000.qcom,ispif"),
 
 	/*VFE clocks*/
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
@@ -5746,6 +5794,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-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 3bb4c57..cf2df18 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -1398,7 +1398,8 @@
 {
 	int rc = 0;
 
-	if (vco_cached_rate != 0) {
+	if ((vco_cached_rate != 0)
+	    && (vco_cached_rate == c->rate)) {
 		rc = vco_set_rate(c, vco_cached_rate);
 		if (rc) {
 			pr_err("%s: vco_set_rate failed. rc=%d\n",
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index b69b155..6ddf340 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -148,7 +148,7 @@
 	void __iomem	*efuse_base;
 
 	/* Process voltage parameters */
-	u32		pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+	u32		pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
 	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
@@ -999,6 +999,7 @@
 	u64 efuse_bits;
 	int rc, process;
 	u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
+	u32 init_v;
 	bool redundant;
 	size_t pvs_bins;
 
@@ -1034,25 +1035,35 @@
 				   ((1 << pvs_fuse[2]) - 1);
 
 	pvs_bins = 1 << pvs_fuse[2];
-	rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
-					cpr_vreg->pvs_bin_process,
-					pvs_bins);
+
+	rc = of_property_read_u32_array(of_node, "qcom,pvs-init-voltage",
+					cpr_vreg->pvs_init_v, pvs_bins);
 	if (rc < 0) {
-		pr_err("pvs-bin-process missing: rc=%d\n", rc);
+		pr_err("pvs-init-voltage missing: rc=%d\n", rc);
 		return rc;
 	}
 
-	process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
-	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)\n",
-		pvs_fuse[0], efuse_bits, pvs_fuse[2],
-		cpr_vreg->pvs_bin, process);
+	init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
+	for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
+		if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+			break;
+	}
 
-	if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
-		pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
-		       cpr_vreg->pvs_bin, process);
+	if (process == APC_PVS_NO) {
+		process = APC_PVS_SLOW;
+		cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+		cpr_vreg->ceiling_max = init_v;
+	} else if (process == APC_PVS_FAST &&
+		init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
 		process = APC_PVS_SLOW;
 	}
 
+	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
+		pvs_fuse[0], efuse_bits, pvs_fuse[2],
+		cpr_vreg->pvs_bin, process);
+	pr_info("pvs initial turbo voltage_= from %u to %u\n",
+		init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+
 	cpr_vreg->process = process;
 
 	return 0;
@@ -1263,10 +1274,6 @@
 			     quot[CPR_CORNER_NORMAL])
 					<= CPR_FUSE_MIN_QUOT_DIFF)
 				valid_fuse = false;
-			else if ((quot[CPR_CORNER_NORMAL] -
-				  quot[CPR_CORNER_SVS])
-					<= CPR_FUSE_MIN_QUOT_DIFF)
-				valid_fuse = false;
 		} else {
 			valid_fuse = false;
 		}
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index bd1a4a2..122ffaa 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -114,6 +114,8 @@
 	TLMM_ETM_MODE_REG = 0x2014,
 	TLMM_SDC2_HDRV_PULL_CTL = 0x2048,
 	TLMM_SPARE_REG = 0x2024,
+	TLMM_CDC_HDRV_CTL = 0x2054,
+	TLMM_CDC_HDRV_PULL_CTL = 0x2058,
 };
 
 void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val);
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 7cfbd93..c4db727 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -101,6 +101,7 @@
  * @asid:         List of ASID and their usage count (index is ASID value).
  * @ctx_attach_count: Count of how many context are attached.
  * @bus_client  : Bus client needed to vote for bus bandwidth.
+ * @needs_rem_spinlock  : 1 if remote spinlock is needed, 0 otherwise
  *
  * A msm_iommu_drvdata holds the global driver data about a single piece
  * of an IOMMU hardware instance.
@@ -125,6 +126,7 @@
 	int *asid;
 	unsigned int ctx_attach_count;
 	unsigned int bus_client;
+	int needs_rem_spinlock;
 };
 
 /**
@@ -146,8 +148,8 @@
 	int (*iommu_clk_on)(struct msm_iommu_drvdata *);
 	void (*iommu_clk_off)(struct msm_iommu_drvdata *);
 	void * (*iommu_lock_initialize)(void);
-	void (*iommu_lock_acquire)(void);
-	void (*iommu_lock_release)(void);
+	void (*iommu_lock_acquire)(unsigned int need_extra_lock);
+	void (*iommu_lock_release)(unsigned int need_extra_lock);
 };
 
 void msm_iommu_add_drv(struct msm_iommu_drvdata *drv);
@@ -277,32 +279,21 @@
 }
 #endif
 
-#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
-void msm_iommu_remote_p0_spin_lock(void);
-void msm_iommu_remote_p0_spin_unlock(void);
+#ifdef CONFIG_MSM_IOMMU_SYNC
+void msm_iommu_remote_p0_spin_lock(unsigned int need_lock);
+void msm_iommu_remote_p0_spin_unlock(unsigned int need_lock);
 
 #define msm_iommu_remote_lock_init() _msm_iommu_remote_spin_lock_init()
-#define msm_iommu_remote_spin_lock() msm_iommu_remote_p0_spin_lock()
-#define msm_iommu_remote_spin_unlock() msm_iommu_remote_p0_spin_unlock()
+#define msm_iommu_remote_spin_lock(need_lock) \
+				msm_iommu_remote_p0_spin_lock(need_lock)
+#define msm_iommu_remote_spin_unlock(need_lock) \
+				msm_iommu_remote_p0_spin_unlock(need_lock)
 #else
 #define msm_iommu_remote_lock_init()
-#define msm_iommu_remote_spin_lock()
-#define msm_iommu_remote_spin_unlock()
+#define msm_iommu_remote_spin_lock(need_lock)
+#define msm_iommu_remote_spin_unlock(need_lock)
 #endif
 
-/* Allows kgsl iommu driver to acquire lock */
-#define msm_iommu_lock() \
-	do { \
-		msm_iommu_mutex_lock(); \
-		msm_iommu_remote_spin_lock(); \
-	} while (0)
-
-#define msm_iommu_unlock() \
-	do { \
-		msm_iommu_remote_spin_unlock(); \
-		msm_iommu_mutex_unlock(); \
-	} while (0)
-
 #ifdef CONFIG_MSM_IOMMU
 /*
  * Look up an IOMMU context device by its context name. NULL if none found.
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8084.h b/arch/arm/mach-msm/include/mach/msm_iomap-8084.h
index 43f1de0..fe68524 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8084.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8084.h
@@ -31,6 +31,9 @@
 #define APQ8084_TLMM_PHYS	0xFD510000
 #define APQ8084_TLMM_SIZE	SZ_16K
 
+#define APQ8084_QGIC_CPU_PHYS	0xF9002000
+#define APQ8084_QGIC_CPU_SIZE	SZ_4K
+
 #ifdef CONFIG_DEBUG_APQ8084_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
index f460a4e..2ae36a5 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
@@ -28,6 +28,9 @@
 #define MPQ8092_QGIC_DIST_PHYS	0xF9000000
 #define MPQ8092_QGIC_DIST_SIZE	SZ_4K
 
+#define MPQ8092_QGIC_CPU_PHYS	0xF9002000
+#define MPQ8092_QGIC_CPU_SIZE	SZ_4K
+
 #define MPQ8092_TLMM_PHYS	0xFD510000
 #define MPQ8092_TLMM_SIZE	SZ_16K
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
index 327c1ea..adf66ff 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
@@ -28,6 +28,9 @@
 #define MSM8226_QGIC_DIST_PHYS	0xF9000000
 #define MSM8226_QGIC_DIST_SIZE	SZ_4K
 
+#define MSM8226_QGIC_CPU_PHYS	0xF9002000
+#define MSM8226_QGIC_CPU_SIZE	SZ_4K
+
 #define MSM8226_APCS_GCC_PHYS	0xF9011000
 #define MSM8226_APCS_GCC_SIZE	SZ_4K
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 18e448d..4431d71 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -27,6 +27,9 @@
 #define MSM8610_QGIC_DIST_PHYS	0xF9000000
 #define MSM8610_QGIC_DIST_SIZE	SZ_4K
 
+#define MSM8610_QGIC_CPU_PHYS	0xF9002000
+#define MSM8610_QGIC_CPU_SIZE	SZ_4K
+
 #define MSM8610_APCS_GCC_PHYS	0xF9011000
 #define MSM8610_APCS_GCC_SIZE	SZ_4K
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
index ec3c210..4072f2d 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -28,6 +28,9 @@
 #define MSM8974_QGIC_DIST_PHYS	0xF9000000
 #define MSM8974_QGIC_DIST_SIZE	SZ_4K
 
+#define MSM8974_QGIC_CPU_PHYS	0xF9002000
+#define MSM8974_QGIC_CPU_SIZE	SZ_4K
+
 #define MSM8974_TLMM_PHYS	0xFD510000
 #define MSM8974_TLMM_SIZE	SZ_16K
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
index 31b19b3..ee5a413 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -28,6 +28,9 @@
 #define MSM9625_QGIC_DIST_PHYS	0xF9000000
 #define MSM9625_QGIC_DIST_SIZE	SZ_4K
 
+#define MSM9625_QGIC_CPU_PHYS	0xF9002000
+#define MSM9625_QGIC_CPU_SIZE	SZ_4K
+
 #define MSM9625_TMR_PHYS	0xF9021000
 #define MSM9625_TMR_SIZE	SZ_4K
 
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 5556db9..19f9c0e 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -26,6 +26,18 @@
 	NUM_SMEM_SUBSYSTEMS,
 };
 
+/*
+ * Flag options for the XXX_to_proc() API
+ *
+ * SMEM_ITEM_CACHED_FLAG - Indicates this operation should use cachable smem
+ *
+ * SMEM_ANY_HOST_FLAG - Indicates this operation should not apply to smem items
+ *                      which are limited to a specific host pairing.  Will
+ *                      cause this operation to ignore the to_proc parameter.
+ */
+#define SMEM_ITEM_CACHED_FLAG 1
+#define SMEM_ANY_HOST_FLAG 2
+
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
 
 enum {
@@ -145,6 +157,15 @@
 void *smem_get_entry(unsigned id, unsigned *size);
 void *smem_find(unsigned id, unsigned size);
 
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags);
+void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags);
+void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags);
+void *smem_get_entry_to_proc(unsigned id, unsigned *size, unsigned to_proc,
+								unsigned flags);
+
 /**
  * smem_get_entry_no_rlock - Get existing item without using remote spinlock
  *
@@ -193,6 +214,26 @@
 {
 	return NULL;
 }
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_get_entry_to_proc(unsigned id, unsigned *size,
+					unsigned to_proc, unsigned flags)
+{
+	return NULL;
+}
 void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out)
 {
 	return NULL;
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index b06189f..6b3d590 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -50,6 +50,7 @@
 #define machine_is_msm8610()	of_machine_is_compatible("qcom,msm8610")
 #define machine_is_msm8226()	of_machine_is_compatible("qcom,msm8226")
 #define machine_is_apq8074()	of_machine_is_compatible("qcom,apq8074")
+#define machine_is_msm8926()	of_machine_is_compatible("qcom,msm8926")
 
 #define early_machine_is_msm8610()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
@@ -80,6 +81,7 @@
 #define machine_is_msm8610()		0
 #define machine_is_msm8226()		0
 #define machine_is_apq8074()		0
+#define machine_is_msm8926()		0
 
 #define early_machine_is_msm8610()	0
 #define early_machine_is_mpq8092()	0
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index f736b30..d1c8500 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -299,6 +299,7 @@
 #ifdef CONFIG_ARCH_MSM8974
 static struct map_desc msm_8974_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MSM8974),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8974),
 	MSM_CHIP_DEVICE(TLMM, MSM8974),
 	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8974),
 	{
@@ -322,6 +323,7 @@
 #ifdef CONFIG_ARCH_APQ8084
 static struct map_desc msm_8084_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, APQ8084),
+	MSM_CHIP_DEVICE(QGIC_CPU, APQ8084),
 	MSM_CHIP_DEVICE(TLMM, APQ8084),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
@@ -504,6 +506,7 @@
 #ifdef CONFIG_ARCH_MSM9625
 static struct map_desc msm9625_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MSM9625),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM9625),
 	MSM_CHIP_DEVICE(TLMM, MSM9625),
 	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM9625),
 	MSM_CHIP_DEVICE(TMR, MSM9625),
@@ -547,6 +550,7 @@
 #ifdef CONFIG_ARCH_MPQ8092
 static struct map_desc mpq8092_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MPQ8092),
+	MSM_CHIP_DEVICE(QGIC_CPU, MPQ8092),
 	MSM_CHIP_DEVICE(TLMM, MPQ8092),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
@@ -569,6 +573,7 @@
 #ifdef CONFIG_ARCH_MSM8226
 static struct map_desc msm_8226_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MSM8226),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8226),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8226),
 	MSM_CHIP_DEVICE(TLMM, MSM8226),
 	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8226),
@@ -594,6 +599,7 @@
 #ifdef CONFIG_ARCH_MSM8610
 static struct map_desc msm8610_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MSM8610),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8610),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
 	MSM_CHIP_DEVICE(TLMM, MSM8610),
 	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 6fe945c..ce66531 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -298,6 +298,8 @@
 		pr_err("%s: failure\n", __func__);
 		return NULL;
 	}
+	memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
+	/* TODO: Copy optional headers, if available */
 
 	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!pkt_fragment_q) {
@@ -323,6 +325,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt_fragment_q);
+	/* TODO: Free optional headers, if present */
 	kfree(cloned_pkt);
 	return NULL;
 }
@@ -361,6 +364,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt->pkt_fragment_q);
+	/* TODO: Free Optional headers, if present */
 	kfree(pkt);
 	return;
 }
@@ -373,6 +377,8 @@
 	int first = 1, offset = 0;
 	int skb_size, data_size;
 	void *data;
+	int last = 1;
+	int align_size;
 
 	skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!skb_head) {
@@ -382,10 +388,13 @@
 	skb_queue_head_init(skb_head);
 
 	data_size = buf_len;
+	align_size = ALIGN_SIZE(data_size);
 	while (offset != buf_len) {
 		skb_size = data_size;
 		if (first)
 			skb_size += IPC_ROUTER_HDR_SIZE;
+		if (last)
+			skb_size += align_size;
 
 		skb = alloc_skb(skb_size, GFP_KERNEL);
 		if (!skb) {
@@ -394,6 +403,7 @@
 				goto buf_to_skb_error;
 			}
 			data_size = data_size / 2;
+			last = 0;
 			continue;
 		}
 
@@ -407,6 +417,7 @@
 		skb_queue_tail(skb_head, skb);
 		offset += data_size;
 		data_size = buf_len - offset;
+		last = 1;
 	}
 	return skb_head;
 
@@ -447,7 +458,7 @@
 	return buf;
 }
 
-static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
 {
 	struct sk_buff *temp_skb;
 
@@ -461,6 +472,328 @@
 	kfree(skb_head);
 }
 
+/**
+ * extract_header_v1() - Extract IPC Router header of version 1
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
+	skb_pull(skb, sizeof(struct rr_header_v1));
+	pkt->length -= sizeof(struct rr_header_v1);
+	return 0;
+}
+
+/**
+ * extract_header_v2() - Extract IPC Router header of version 2
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = (struct rr_header_v2 *)skb->data;
+	pkt->hdr.version = (uint32_t)hdr->version;
+	pkt->hdr.type = (uint32_t)hdr->type;
+	pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
+	pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
+	pkt->hdr.size = (uint32_t)hdr->size;
+	pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
+	pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
+	pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
+	skb_pull(skb, sizeof(struct rr_header_v2));
+	pkt->length -= sizeof(struct rr_header_v2);
+	return 0;
+}
+
+/**
+ * extract_header() - Extract IPC Router header
+ * @pkt: Packet from which the header has to be extraced.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function will check if the header version is v1 or v2 and invoke
+ * the corresponding helper function to extract the IPC Router header.
+ */
+static int extract_header(struct rr_packet *pkt)
+{
+	struct sk_buff *temp_skb;
+	int ret;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (temp_skb->data[0] == IPC_ROUTER_V1) {
+		ret = extract_header_v1(pkt, temp_skb);
+	} else if (temp_skb->data[0] == IPC_ROUTER_V2) {
+		ret = extract_header_v2(pkt, temp_skb);
+		/* TODO: Extract optional headers if present */
+	} else {
+		pr_err("%s: Invalid Header version %02x\n",
+			__func__, temp_skb->data[0]);
+		print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
+			       16, 1, temp_skb->data, pkt->length, true);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/**
+ * calc_tx_header_size() - Calculate header size to be reserved in SKB
+ * @pkt: Packet in which the space for header has to be reserved.
+ * @dst_xprt_info: XPRT through which the destination is reachable.
+ *
+ * @return: required header size on success,
+ *          starndard Linux error codes on failure.
+ *
+ * This function is used to calculate the header size that has to be reserved
+ * in a transmit SKB. The header size is calculated based on the XPRT through
+ * which the destination node is reachable.
+ */
+static int calc_tx_header_size(struct rr_packet *pkt,
+			       struct msm_ipc_router_xprt_info *dst_xprt_info)
+{
+	int hdr_size = 0;
+	int xprt_version = 0;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!xprt_info) {
+		rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
+		if (!rt_entry || !(rt_entry->xprt_info)) {
+			pr_err("%s: Node %d is not up\n",
+				__func__, pkt->hdr.dst_node_id);
+			return -ENODEV;
+		}
+
+		xprt_info = rt_entry->xprt_info;
+	}
+	if (xprt_info)
+		xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
+
+	if (xprt_version == IPC_ROUTER_V1) {
+		pkt->hdr.version = IPC_ROUTER_V1;
+		hdr_size = sizeof(struct rr_header_v1);
+	} else if (xprt_version == IPC_ROUTER_V2) {
+		pkt->hdr.version = IPC_ROUTER_V2;
+		hdr_size = sizeof(struct rr_header_v2);
+		/* TODO: Calculate optional header length, if present */
+	} else {
+		pr_err("%s: Invalid xprt_version %d\n",
+			__func__, xprt_version);
+		hdr_size = -EINVAL;
+	}
+
+	return hdr_size;
+}
+
+/**
+ * prepend_header_v1() - Prepend IPC Router header of version 1
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v1 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
+	memcpy(hdr, &pkt->hdr, hdr_size);
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header_v2() - Prepend IPC Router header of version 2
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
+	hdr->version = (uint8_t)pkt->hdr.version;
+	hdr->type = (uint8_t)pkt->hdr.type;
+	hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
+	hdr->size = (uint32_t)pkt->hdr.size;
+	hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
+	hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
+	hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
+	hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
+	/* TODO: Add optional headers, if present */
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header() - Prepend IPC Router header
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @xprt_info: XPRT through which the packet is transmitted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function prepends the header to the packet to be transmitted. The
+ * IPC Router header version to be prepended depends on the XPRT through
+ * which the destination is reachable.
+ */
+static int prepend_header(struct rr_packet *pkt,
+			  struct msm_ipc_router_xprt_info *xprt_info)
+{
+	int hdr_size;
+	struct sk_buff *temp_skb;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr_size = calc_tx_header_size(pkt, xprt_info);
+	if (hdr_size <= 0)
+		return hdr_size;
+
+	if (pkt->hdr.version == IPC_ROUTER_V1)
+		return prepend_header_v1(pkt, hdr_size);
+	else if (pkt->hdr.version == IPC_ROUTER_V2)
+		return prepend_header_v2(pkt, hdr_size);
+	else
+		return -EINVAL;
+}
+
+/**
+ * defragment_pkt() - Defragment and linearize the packet
+ * @pkt: Packet to be linearized.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * Some packets contain fragments of data over multiple SKBs. If an XPRT
+ * does not supported fragmented writes, linearize multiple SKBs into one
+ * single SKB.
+ */
+static int defragment_pkt(struct rr_packet *pkt)
+{
+	struct sk_buff *dst_skb, *src_skb, *temp_skb;
+	int offset = 0, buf_len = 0, copy_len;
+	void *buf;
+	int align_size;
+
+	if (!pkt || pkt->length <= 0) {
+		pr_err("%s: Invalid PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_queue_len(pkt->pkt_fragment_q) == 1)
+		return 0;
+
+	align_size = ALIGN_SIZE(pkt->length);
+	dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
+	if (!dst_skb) {
+		pr_err("%s: could not allocate one skb of size %d\n",
+			__func__, pkt->length);
+		return -ENOMEM;
+	}
+	buf = skb_put(dst_skb, pkt->length);
+	buf_len = pkt->length;
+
+	skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
+		copy_len =  buf_len < src_skb->len ? buf_len : src_skb->len;
+		memcpy(buf + offset, src_skb->data, copy_len);
+		offset += copy_len;
+		buf_len -= copy_len;
+	}
+
+	while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
+	return 0;
+}
+
 static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
 			    struct rr_packet *pkt, int clone)
 {
@@ -515,7 +848,7 @@
 	down_read(&local_ports_lock_lha2);
 	do {
 		next_port_id++;
-		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+		if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
 			next_port_id = 1;
 
 		key = (next_port_id & (LP_HASH_SIZE - 1));
@@ -932,7 +1265,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -973,32 +1306,33 @@
 	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = sizeof(*msg);
 
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
 		hdr->dst_node_id = dst_node_id;
 	else
 		hdr->dst_node_id = xprt_info->remote_node_id;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
-	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
-	pkt->pkt_fragment_q = pkt_fragment_q;
-	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock_lhb2);
-	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		mutex_unlock(&xprt_info->tx_lock_lhb2);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		release_pkt(pkt);
+		return ret;
+	}
+
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
 
 	release_pkt(pkt);
@@ -1074,7 +1408,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -1094,7 +1428,7 @@
 	}
 	skb_queue_head_init(pkt_fragment_q);
 
-	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	pkt_size = sizeof(*msg);
 	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
 	if (!ipc_rtr_pkt) {
 		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
@@ -1103,22 +1437,14 @@
 		return -ENOMEM;
 	}
 
-	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
@@ -1164,70 +1490,60 @@
 	return 0;
 }
 
-static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
-		     struct rr_packet *pkt)
-{
-	struct msm_ipc_router_xprt_info *fwd_xprt_info;
-
-	if (!xprt_info || !pkt)
-		return -EINVAL;
-
-	down_read(&xprt_info_list_lock_lha5);
-	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
-		mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
-		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length,
-						   fwd_xprt_info->xprt);
-		mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-	}
-	up_read(&xprt_info_list_lock_lha5);
-	return 0;
-}
-
 static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
 		       struct rr_packet *pkt)
 {
-	uint32_t dst_node_id;
-	struct sk_buff *head_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *fwd_xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret = 0;
+	int fwd_xprt_option;
 
 	if (!xprt_info || !pkt)
 		return -EINVAL;
 
-	head_pkt = skb_peek(pkt->pkt_fragment_q);
-	if (!head_pkt)
-		return -EINVAL;
-
-	hdr = (struct rr_header *)head_pkt->data;
-	dst_node_id = hdr->dst_node_id;
+	hdr = &(pkt->hdr);
 	down_read(&routing_table_lock_lha3);
-	rt_entry = lookup_routing_table(dst_node_id);
+	rt_entry = lookup_routing_table(hdr->dst_node_id);
 	if (!(rt_entry) || !(rt_entry->xprt_info)) {
-		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Routing table not initialized\n", __func__);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto fm_error1;
 	}
 
 	down_read(&rt_entry->lock_lha4);
 	fwd_xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, fwd_xprt_info);
+	if (ret < 0) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		goto fm_error2;
+	}
+	fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
+	if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0)
+			goto fm_error2;
+	}
+
+	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
 		pr_err("%s: Discarding Command to route back\n", __func__);
 		ret = -EINVAL;
-		goto fwd_msg_out;
+		goto fm_error3;
 	}
 
 	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
 		pr_err("%s: DST in the same cluster\n", __func__);
-		goto fwd_msg_out;
+		ret = 0;
+		goto fm_error3;
 	}
-	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+
+fm_error3:
 	mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-fwd_msg_out:
+fm_error2:
 	up_read(&rt_entry->lock_lha4);
+fm_error1:
 	up_read(&routing_table_lock_lha3);
 
 	return ret;
@@ -1470,7 +1786,7 @@
 }
 
 static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
-			     struct rr_header *hdr)
+			     struct rr_header_v1 *hdr)
 {
 	int i, rc = 0;
 	union rr_control_msg ctl;
@@ -1508,7 +1824,7 @@
 
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
-	ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+	ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
 	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
 						IPC_ROUTER_DUMMY_DEST_NODE);
 	if (rc < 0) {
@@ -1654,7 +1970,7 @@
 	 * to the cluster from which this message is received. Notify the
 	 * local clients waiting for this service.
 	 */
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1677,7 +1993,7 @@
 		 * belong to the cluster from which this message is received.
 		 * Notify the local clients communicating with the service.
 		 */
-		relay_msg(xprt_info, pkt);
+		relay_ctl_msg(xprt_info, msg);
 		post_control_ports(pkt);
 	}
 	up_write(&server_list_lock_lha2);
@@ -1697,7 +2013,7 @@
 		msm_ipc_router_destroy_remote_port(rport_ptr);
 	up_write(&routing_table_lock_lha3);
 
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1707,26 +2023,20 @@
 {
 	union rr_control_msg *msg;
 	int rc = 0;
-	struct sk_buff *temp_ptr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 
-	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+	if (pkt->length != sizeof(*msg)) {
 		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
-			(IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+			sizeof(*msg));
 		return -EINVAL;
 	}
 
-	temp_ptr = skb_peek(pkt->pkt_fragment_q);
-	if (!temp_ptr) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
+	hdr = &(pkt->hdr);
+	msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
+	if (!msg) {
+		pr_err("%s: Error extracting control msg\n", __func__);
+		return -ENOMEM;
 	}
-	hdr = (struct rr_header *)temp_ptr->data;
-	if (!hdr) {
-		pr_err("%s: No data inside the skb\n", __func__);
-		return -EINVAL;
-	}
-	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
 
 	switch (msg->cmd) {
 	case IPC_ROUTER_CTRL_CMD_HELLO:
@@ -1752,17 +2062,17 @@
 		RR("o UNKNOWN(%08x)\n", msg->cmd);
 		rc = -ENOSYS;
 	}
-
+	kfree(msg);
 	return rc;
 }
 
 static void do_read_data(struct work_struct *work)
 {
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct rr_packet *pkt = NULL;
 	struct msm_ipc_port *port_ptr;
-	struct sk_buff *head_skb;
 	struct msm_ipc_router_remote_port *rport_ptr;
+	int ret;
 
 	struct msm_ipc_router_xprt_info *xprt_info =
 		container_of(work,
@@ -1777,24 +2087,15 @@
 			goto fail_data;
 		}
 
-		head_skb = skb_peek(pkt->pkt_fragment_q);
-		if (!head_skb) {
-			pr_err("%s: head_skb is invalid\n", __func__);
+		ret = extract_header(pkt);
+		if (ret < 0)
 			goto fail_data;
-		}
-
-		hdr = (struct rr_header *)(head_skb->data);
+		hdr = &(pkt->hdr);
 		RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
 		     hdr->version, hdr->type, hdr->src_node_id,
-		     hdr->src_port_id, hdr->confirm_rx, hdr->size,
+		     hdr->src_port_id, hdr->control_flag, hdr->size,
 		     hdr->dst_node_id, hdr->dst_port_id);
 
-		if (hdr->version != IPC_ROUTER_VERSION) {
-			pr_err("version %d != %d\n",
-				hdr->version, IPC_ROUTER_VERSION);
-			goto fail_data;
-		}
-
 		if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
 		    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
 		     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
@@ -1803,8 +2104,7 @@
 			continue;
 		}
 
-		if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
-		    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+		if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
 			process_control_msg(xprt_info, pkt);
 			release_pkt(pkt);
 			continue;
@@ -1819,7 +2119,7 @@
 				(hdr->src_port_id & 0xffffff),
 				(hdr->dst_node_id << 24) |
 				(hdr->dst_port_id & 0xffffff),
-				(hdr->type << 24) | (hdr->confirm_rx << 16) |
+				(hdr->type << 24) | (hdr->control_flag << 16) |
 				(hdr->size & 0xffff));
 		}
 #endif
@@ -1906,6 +2206,7 @@
 	ctl.srv.port_id = port_ptr->this_port.port_id;
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = SERVER_PORT;
 	port_ptr->mode_info.mode = MULTI_LINK_MODE;
@@ -1957,6 +2258,7 @@
 				      port_ptr->this_port.port_id);
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = CLIENT_PORT;
 	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1967,8 +2269,7 @@
 			uint32_t port_id,
 			struct sk_buff_head *data)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_port *port_ptr;
 	struct rr_packet *pkt;
 	int ret_len;
@@ -1983,34 +2284,22 @@
 		pr_err("%s: New pkt create failed\n", __func__);
 		return -ENOMEM;
 	}
-
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		release_pkt(pkt);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		release_pkt(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	down_read(&local_ports_lock_lha2);
 	port_ptr = msm_ipc_router_lookup_local_port(port_id);
 	if (!port_ptr) {
 		pr_err("%s: Local port %d not present\n", __func__, port_id);
 		up_read(&local_ports_lock_lha2);
+		pkt->pkt_fragment_q = NULL;
 		release_pkt(pkt);
 		return -ENODEV;
 	}
@@ -2027,35 +2316,26 @@
 				struct msm_ipc_router_remote_port *rport_ptr,
 				struct rr_packet *pkt)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	struct msm_ipc_resume_tx_port  *resume_tx_port;
+	struct sk_buff *temp_skb;
+	int xprt_option;
 	int ret;
+	int align_size;
 
 	if (!rport_ptr || !src || !pkt)
 		return -EINVAL;
 
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = rport_ptr->node_id;
 	hdr->dst_port_id = rport_ptr->port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	mutex_lock(&rport_ptr->quota_lock_lhb2);
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
@@ -2083,7 +2363,7 @@
 	}
 	rport_ptr->tx_quota_cnt++;
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
-		hdr->confirm_rx = 1;
+		hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
 	mutex_unlock(&rport_ptr->quota_lock_lhb2);
 
 	rt_entry = lookup_routing_table(hdr->dst_node_id);
@@ -2094,6 +2374,25 @@
 	}
 	down_read(&rt_entry->lock_lha4);
 	xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		up_read(&rt_entry->lock_lha4);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		return ret;
+	}
+	xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
+	if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0) {
+			up_read(&rt_entry->lock_lha4);
+			return ret;
+		}
+	}
+
+	temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
+	align_size = ALIGN_SIZE(pkt->length);
+	skb_put(temp_skb, align_size);
+	pkt->length += align_size;
 	mutex_lock(&xprt_info->tx_lock_lhb2);
 	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
@@ -2107,10 +2406,10 @@
 
 	RAW_HDR("[w rr_h] "
 		"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
-		"confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+		"control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
 		hdr->version, type_to_str(hdr->type),
 		hdr->src_node_id, hdr->src_port_id,
-		hdr->confirm_rx, hdr->size,
+		hdr->control_flag, hdr->size,
 		hdr->dst_node_id, hdr->dst_port_id);
 
 #if defined(CONFIG_MSM_SMD_LOGGING)
@@ -2123,13 +2422,13 @@
 			(hdr->src_port_id & 0xffffff),
 			(hdr->dst_node_id << 24) |
 			(hdr->dst_port_id & 0xffffff),
-			(hdr->type << 24) | (hdr->confirm_rx << 16) |
+			(hdr->type << 24) | (hdr->control_flag << 16) |
 			(hdr->size & 0xffff));
 	}
 #endif
 #endif
 
-	return pkt->length;
+	return hdr->size;
 }
 
 int msm_ipc_router_send_to(struct msm_ipc_port *src,
@@ -2203,6 +2502,8 @@
 
 	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
 	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pkt->pkt_fragment_q = NULL;
 	release_pkt(pkt);
 
 	return ret;
@@ -2222,11 +2523,10 @@
 	}
 
 	ret = msm_ipc_router_send_to(src, out_skb_head, dest);
-	if (ret == -EAGAIN)
-		return ret;
 	if (ret < 0) {
-		pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
-			__func__, ret);
+		if (ret != -EAGAIN)
+			pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
+				__func__, ret);
 		msm_ipc_router_free_skb(out_skb_head);
 		return ret;
 	}
@@ -2248,7 +2548,7 @@
 static int msm_ipc_router_send_resume_tx(void *data)
 {
 	union rr_control_msg msg;
-	struct rr_header *hdr = (struct rr_header *)data;
+	struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret;
 
@@ -2278,14 +2578,12 @@
 }
 
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **read_pkt,
 			size_t buf_len)
 {
 	struct rr_packet *pkt;
-	struct sk_buff *head_skb;
-	int ret;
 
-	if (!port_ptr || !data)
+	if (!port_ptr || !read_pkt)
 		return -EINVAL;
 
 	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2295,26 +2593,19 @@
 	}
 
 	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
-	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+	if ((buf_len) && (pkt->hdr.size > buf_len)) {
 		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		return -ETOOSMALL;
 	}
 	list_del(&pkt->list);
 	if (list_empty(&port_ptr->port_rx_q))
 		wake_unlock(&port_ptr->port_rx_wake_lock);
-	*data = pkt->pkt_fragment_q;
-	ret = pkt->length;
+	*read_pkt = pkt;
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
-	kfree(pkt);
-	head_skb = skb_peek(*data);
-	if (!head_skb) {
-		pr_err("%s: Socket Buffer not found", __func__);
-		return -EFAULT;
-	}
-	if (((struct rr_header *)(head_skb->data))->confirm_rx)
-		msm_ipc_router_send_resume_tx((void *)(head_skb->data));
+	if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
+		msm_ipc_router_send_resume_tx(&pkt->hdr);
 
-	return ret;
+	return pkt->length;
 }
 
 /**
@@ -2362,7 +2653,7 @@
 /**
  * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
  * @port_ptr: Pointer to the local port
- * @data : Pointer to the socket buffer head
+ * @pkt : Pointer to the router-to-router packet
  * @src: Pointer to local port address
  * @timeout: < 0 timeout indicates infinite wait till a message arrives.
  *	     > 0 timeout indicates the wait time.
@@ -2383,31 +2674,30 @@
  * of bytes that are read.
  */
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-			     struct sk_buff_head **data,
+			     struct rr_packet **pkt,
 			     struct msm_ipc_addr *src,
 			     long timeout)
 {
 	int ret, data_len, align_size;
 	struct sk_buff *temp_skb;
-	struct rr_header *hdr = NULL;
+	struct rr_header_v1 *hdr = NULL;
 
-	if (!port_ptr || !data) {
+	if (!port_ptr || !pkt) {
 		pr_err("%s: Invalid pointers being passed\n", __func__);
 		return -EINVAL;
 	}
 
-	*data = NULL;
+	*pkt = NULL;
 
 	ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
 	if (ret)
 		return ret;
 
-	ret = msm_ipc_router_read(port_ptr, data, 0);
-	if (ret <= 0 || !(*data))
+	ret = msm_ipc_router_read(port_ptr, pkt, 0);
+	if (ret <= 0 || !(*pkt))
 		return ret;
 
-	temp_skb = skb_peek(*data);
-	hdr = (struct rr_header *)(temp_skb->data);
+	hdr = &((*pkt)->hdr);
 	if (src) {
 		src->addrtype = MSM_IPC_ADDR_ID;
 		src->addr.port_addr.node_id = hdr->src_node_id;
@@ -2415,10 +2705,9 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
 	align_size = ALIGN_SIZE(data_len);
 	if (align_size) {
-		temp_skb = skb_peek_tail(*data);
+		temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
 		skb_trim(temp_skb, (temp_skb->len - align_size));
 	}
 	return data_len;
@@ -2429,11 +2718,10 @@
 			    unsigned char **data,
 			    unsigned int *len)
 {
-	struct sk_buff_head *in_skb_head;
+	struct rr_packet *pkt;
 	int ret;
 
-	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
-
+	ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
 	if (ret < 0) {
 		if (ret != -ENOMSG)
 			pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
@@ -2441,12 +2729,12 @@
 		return ret;
 	}
 
-	*data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+	*data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
 	if (!(*data))
 		pr_err("%s: Buf conversion failed\n", __func__);
 
 	*len = ret;
-	msm_ipc_router_free_skb(in_skb_head);
+	release_pkt(pkt);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 7bfc52b..8ffd661 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -24,12 +24,17 @@
 #include <net/sock.h>
 
 /* definitions for the R2R wire protcol */
-#define IPC_ROUTER_VERSION			1
+#define IPC_ROUTER_V1		1
+/*
+ * Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
+ * with an existing alternate transport in user-space, if needed.
+ */
+#define IPC_ROUTER_V2		3
 
-#define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
-#define IPC_ROUTER_ADDRESS			0xfffffffe
+#define IPC_ROUTER_ADDRESS			0x0000FFFF
 
 #define IPC_ROUTER_NID_LOCAL			1
+#define MAX_IPC_PKT_SIZE 66000
 
 #define IPC_ROUTER_CTRL_CMD_DATA		1
 #define IPC_ROUTER_CTRL_CMD_HELLO		2
@@ -55,6 +60,11 @@
 #define ALL_SERVICE 0xFFFFFFFF
 #define ALL_INSTANCE 0xFFFFFFFF
 
+#define CONTROL_FLAG_CONFIRM_RX 0x1
+#define CONTROL_FLAG_OPT_HDR 0x2
+
+#define FRAG_PKT_WRITE_ENABLE 0x1
+
 enum {
 	CLIENT_PORT,
 	SERVER_PORT,
@@ -68,10 +78,22 @@
 	MULTI_LINK_MODE,
 };
 
+/**
+ * rr_control_msg - Control message structure
+ * @cmd: Command identifier for HELLO message in Version 1.
+ * @hello: Message structure for HELLO message in Version 2.
+ * @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
+ * @cli: Message structure for REMOVE_CLIENT event.
+ */
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
 		uint32_t cmd;
+		uint32_t magic;
+		uint32_t capability;
+	} hello;
+	struct {
+		uint32_t cmd;
 		uint32_t service;
 		uint32_t instance;
 		uint32_t node_id;
@@ -84,22 +106,67 @@
 	} cli;
 };
 
-struct rr_header {
+/**
+ * rr_header_v1 - IPC Router header version 1
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @control_flag: Flag to indicate flow control.
+ * @size: Size of the IPC Router payload.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v1 {
 	uint32_t version;
 	uint32_t type;
 	uint32_t src_node_id;
 	uint32_t src_port_id;
-	uint32_t confirm_rx;
+	uint32_t control_flag;
 	uint32_t size;
 	uint32_t dst_node_id;
 	uint32_t dst_port_id;
 };
 
-#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
-#define MAX_IPC_PKT_SIZE 66000
+/**
+ * rr_header_v2 - IPC Router header version 2
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @control_flag: Flags to indicate flow control, optional header etc.
+ * @size: Size of the IPC Router payload.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v2 {
+	uint8_t version;
+	uint8_t type;
+	uint16_t control_flag;
+	uint32_t size;
+	uint16_t src_node_id;
+	uint16_t src_port_id;
+	uint16_t dst_node_id;
+	uint16_t dst_port_id;
+} __attribute__((__packed__));
 
+union rr_header {
+	struct rr_header_v1 hdr_v1;
+	struct rr_header_v2 hdr_v2;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
+
+/**
+ * rr_packet - Router to Router packet structure
+ * @list: Pointer to prev & next packets in a port's rx list.
+ * @hdr: Header information extracted from or prepended to a packet.
+ * @pkt_fragment_q: Queue of SKBs containing payload.
+ * @length: Length of data in the chain of SKBs
+ */
 struct rr_packet {
 	struct list_head list;
+	struct rr_header_v1 hdr;
 	struct sk_buff_head *pkt_fragment_q;
 	uint32_t length;
 };
@@ -110,11 +177,28 @@
 	void *default_pil;
 };
 
+/**
+ * msm_ipc_router_xprt - Structure to hold XPRT specific information
+ * @name: Name of the XPRT.
+ * @link_id: Network cluster ID to which the XPRT belongs to.
+ * @priv: XPRT's private data.
+ * @get_version: Method to get header version supported by the XPRT.
+ * @get_option: Method to get XPRT specific options.
+ * @read_avail: Method to get data size available to be read from the XPRT.
+ * @read: Method to read data from the XPRT.
+ * @write_avail: Method to get write space available in the XPRT.
+ * @write: Method to write data to the XPRT.
+ * @close: Method to close the XPRT.
+ * @sft_close_done: Method to indicate to the XPRT that handling of reset
+ *                  event is complete.
+ */
 struct msm_ipc_router_xprt {
 	char *name;
 	uint32_t link_id;
 	void *priv;
 
+	int (*get_version)(struct msm_ipc_router_xprt *xprt);
+	int (*get_option)(struct msm_ipc_router_xprt *xprt);
 	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
 	int (*read)(void *data, uint32_t len,
 		    struct msm_ipc_router_xprt *xprt);
@@ -141,12 +225,12 @@
 			   struct sk_buff_head *data,
 			   struct msm_ipc_addr *dest);
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **pkt,
 			size_t buf_len);
 int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
 
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-		      struct sk_buff_head **data,
+		      struct rr_packet **pkt,
 		      struct msm_ipc_addr *src_addr,
 		      long timeout);
 int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
@@ -173,4 +257,5 @@
 static inline void msm_ipc_unload_default_node(void *pil) { }
 #endif
 
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head);
 #endif
diff --git a/arch/arm/mach-msm/ipc_router_hsic_xprt.c b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
new file mode 100644
index 0000000..0427c1c
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
@@ -0,0 +1,503 @@
+/* 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.
+ */
+
+/*
+ * IPC ROUTER HSIC XPRT module.
+ */
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/ipc_bridge.h>
+#include <mach/subsystem_restart.h>
+
+#include "ipc_router.h"
+
+static int msm_ipc_router_hsic_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_hsic_xprt_debug_mask) \
+	pr_info(x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#endif
+
+#define NUM_HSIC_XPRTS 1
+#define XPRT_NAME_LEN 32
+
+/**
+ * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT strucutre
+ * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
+ * @pdev: Platform device registered by IPC Bridge function driver.
+ * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
+ * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
+ * @in_pkt: Pointer to any partially read packet.
+ * @ss_reset_lock: Lock to protect access to the ss_reset flag.
+ * @sft_close_complete: Variable to indicate completion of SSR handling
+ *                      by IPC Router.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ * @xprt_option: XPRT specific options to be handled by IPC Router.
+ */
+struct msm_ipc_router_hsic_xprt {
+	struct msm_ipc_router_xprt xprt;
+	struct platform_device *pdev;
+	struct workqueue_struct *hsic_xprt_wq;
+	struct delayed_work read_work;
+	struct rr_packet *in_pkt;
+	struct mutex ss_reset_lock;
+	int ss_reset;
+	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
+};
+
+struct msm_ipc_router_hsic_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void hsic_xprt_read_data(struct work_struct *work);
+
+/**
+ * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
+ * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
+ * @link_id: Network Cluster ID to which this XPRT belongs to.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ */
+struct msm_ipc_router_hsic_xprt_config {
+	char ch_name[XPRT_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	int hsic_pdev_id;
+	uint32_t link_id;
+	unsigned xprt_version;
+};
+
+struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
+	{"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
+};
+
+static struct msm_ipc_router_hsic_xprt hsic_remote_xprt[NUM_HSIC_XPRTS];
+
+/**
+ * find_hsic_xprt_cfg() - Find the config info specific to an HSIC endpoint
+ * @pdev: Platform device registered by HSIC's ipc_bridge driver
+ *
+ * @return: Index to the entry in the hsic_remote_xprt table if matching
+ *          endpoint is found, < 0 on error.
+ *
+ * This function is used to find the configuration information specific to
+ * an HSIC endpoint from the hsic_remote_xprt table.
+ */
+static int find_hsic_xprt_cfg(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_HSIC_XPRTS; i++) {
+		/* TODO: Update the condition for multiple hsic links */
+		if (!strncmp(pdev->name, hsic_xprt_cfg[i].ch_name, 32))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
+ *                                          supported by the XPRT
+ * @xprt: XPRT for which the version information is required.
+ *
+ * @return: IPC Router header version supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_version;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
+ * @xprt: XPRT for which the option information is required.
+ *
+ * @return: Options supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_option;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write_avail() - Get available write space
+ * @xprt: XPRT for which the available write space info. is required.
+ *
+ * @return: Write space in bytes on success, 0 on SSR.
+ */
+static int msm_ipc_router_hsic_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct ipc_bridge_platform_data *pdata;
+	int write_avail;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
+		write_avail = 0;
+	} else {
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		write_avail = pdata->max_write_size;
+	}
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return write_avail;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write() - Write to XPRT
+ * @data: Data to be written to the XPRT.
+ * @len: Length of the data to be written.
+ * @xprt: XPRT to which the data has to be written.
+ *
+ * @return: Data Length on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_write(void *data,
+		uint32_t len, struct msm_ipc_router_xprt *xprt)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *skb;
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	int ret;
+
+	if (!pkt || pkt->length != len || !xprt) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset) {
+		pr_err("%s: Trying to write on a reset link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENETRESET;
+	}
+
+	if (!hsic_xprtp->pdev) {
+		pr_err("%s: Trying to write on a closed link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENODEV;
+	}
+
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (!pdata || !pdata->write) {
+		pr_err("%s on a uninitialized link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EFAULT;
+	}
+
+	skb = skb_peek(pkt->pkt_fragment_q);
+	if (!skb) {
+		pr_err("%s SKB is NULL\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EINVAL;
+	}
+	D("%s: About to write %d bytes\n", __func__, len);
+	ret = pdata->write(hsic_xprtp->pdev, skb->data, skb->len);
+	if (ret == skb->len)
+		ret = len;
+	D("%s: Finished writing %d bytes\n", __func__, len);
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return ret;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_close() - Close the XPRT
+ * @xprt: XPRT which needs to be closed.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_close(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	struct ipc_bridge_platform_data *pdata;
+
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	hsic_xprtp->ss_reset = 1;
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	flush_workqueue(hsic_xprtp->hsic_xprt_wq);
+	destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(hsic_xprtp->pdev);
+	hsic_xprtp->pdev = NULL;
+	return 0;
+}
+
+/**
+ * hsic_xprt_read_data() - Read work to read from the XPRT
+ * @work: Read work to be executed.
+ *
+ * This function is a read work item queued on a XPRT specific workqueue.
+ * The work parameter contains information regarding the XPRT on which this
+ * read work has to be performed. The work item keeps reading from the HSIC
+ * endpoint, until the endpoint returns an error.
+ */
+static void hsic_xprt_read_data(struct work_struct *work)
+{
+	int pkt_size;
+	struct sk_buff *skb = NULL;
+	void *data;
+	struct ipc_bridge_platform_data *pdata;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
+
+	while (1) {
+		mutex_lock(&hsic_xprtp->ss_reset_lock);
+		if (hsic_xprtp->ss_reset) {
+			mutex_unlock(&hsic_xprtp->ss_reset_lock);
+			break;
+		}
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		while (!hsic_xprtp->in_pkt) {
+			hsic_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						     GFP_KERNEL);
+			if (hsic_xprtp->in_pkt)
+				break;
+			pr_err("%s: packet allocation failure\n", __func__);
+			msleep(100);
+		}
+		while (!hsic_xprtp->in_pkt->pkt_fragment_q) {
+			hsic_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (hsic_xprtp->in_pkt->pkt_fragment_q)
+				break;
+			pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+				__func__);
+			msleep(100);
+		}
+		skb_queue_head_init(hsic_xprtp->in_pkt->pkt_fragment_q);
+		D("%s: Allocated rr_packet\n", __func__);
+
+		while (!skb) {
+			skb = alloc_skb(pdata->max_read_size, GFP_KERNEL);
+			if (skb)
+				break;
+			pr_err("%s: Couldn't alloc SKB\n", __func__);
+			msleep(100);
+		}
+		data = skb_put(skb, pdata->max_read_size);
+		pkt_size = pdata->read(hsic_xprtp->pdev, data,
+					pdata->max_read_size);
+		if (pkt_size < 0) {
+			pr_err("%s: Error %d @ read operation\n",
+				__func__, pkt_size);
+			kfree_skb(skb);
+			kfree(hsic_xprtp->in_pkt->pkt_fragment_q);
+			kfree(hsic_xprtp->in_pkt);
+			break;
+		}
+		skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
+		hsic_xprtp->in_pkt->length = pkt_size;
+		D("%s: Packet size read %d\n", __func__, pkt_size);
+		msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
+			IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
+		release_pkt(hsic_xprtp->in_pkt);
+		hsic_xprtp->in_pkt = NULL;
+		skb = NULL;
+	}
+}
+
+/**
+ * hsic_xprt_sft_close_done() - Completion of XPRT reset
+ * @xprt: XPRT on which the reset operation is complete.
+ *
+ * This function is used by IPC Router to signal this HSIC XPRT Abstraction
+ * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
+ */
+static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	complete_all(&hsic_xprtp->sft_close_complete);
+}
+
+/**
+ * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver unregisters
+ * a platform device, mapped to an HSIC endpoint, during SSR.
+ */
+static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
+{
+	int id;
+	struct ipc_bridge_platform_data *pdata;
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	mutex_lock(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 1;
+	mutex_unlock(&hsic_remote_xprt[id].ss_reset_lock);
+	flush_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	init_completion(&hsic_remote_xprt[id].sft_close_complete);
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	wait_for_completion(&hsic_remote_xprt[id].sft_close_complete);
+	hsic_remote_xprt[id].pdev = NULL;
+	pdata = pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(pdev);
+	return 0;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver registers
+ * a platform device, mapped to an HSIC endpoint.
+ */
+static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+	int id;		/*Index into the hsic_xprt_cfg table*/
+	struct ipc_bridge_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata || !pdata->open || !pdata->read ||
+	    !pdata->write || !pdata->close) {
+		pr_err("%s: pdata or pdata->operations is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	hsic_remote_xprt[id].hsic_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!hsic_remote_xprt[id].hsic_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	hsic_remote_xprt[id].xprt.name = hsic_xprt_cfg[id].xprt_name;
+	hsic_remote_xprt[id].xprt.link_id = hsic_xprt_cfg[id].link_id;
+	hsic_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_hsic_get_xprt_version;
+	hsic_remote_xprt[id].xprt.get_option =
+		 msm_ipc_router_hsic_get_xprt_option;
+	hsic_remote_xprt[id].xprt.read_avail = NULL;
+	hsic_remote_xprt[id].xprt.read = NULL;
+	hsic_remote_xprt[id].xprt.write_avail =
+		msm_ipc_router_hsic_remote_write_avail;
+	hsic_remote_xprt[id].xprt.write = msm_ipc_router_hsic_remote_write;
+	hsic_remote_xprt[id].xprt.close = msm_ipc_router_hsic_remote_close;
+	hsic_remote_xprt[id].xprt.sft_close_done = hsic_xprt_sft_close_done;
+	hsic_remote_xprt[id].xprt.priv = NULL;
+
+	hsic_remote_xprt[id].in_pkt = NULL;
+	INIT_DELAYED_WORK(&hsic_remote_xprt[id].read_work, hsic_xprt_read_data);
+	mutex_init(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 0;
+	hsic_remote_xprt[id].xprt_version = hsic_xprt_cfg[id].xprt_version;
+	hsic_remote_xprt[id].xprt_option = 0;
+
+	rc = pdata->open(pdev);
+	if (rc < 0) {
+		pr_err("%s: Channel open failed for %s.%d\n",
+			__func__, pdev->name, pdev->id);
+		destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+		return rc;
+	}
+	hsic_remote_xprt[id].pdev = pdev;
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	queue_delayed_work(hsic_remote_xprt[id].hsic_xprt_wq,
+			   &hsic_remote_xprt[id].read_work, 0);
+	return 0;
+}
+
+static struct platform_driver msm_ipc_router_hsic_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_hsic_remote_probe,
+		.remove		= msm_ipc_router_hsic_remote_remove,
+		.driver		= {
+				.name	= "ipc_bridge",
+				.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static int __init msm_ipc_router_hsic_init(void)
+{
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS);
+	for (i = 0; i < ARRAY_SIZE(msm_ipc_router_hsic_remote_driver); i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_hsic_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for xprt%d. Continuing...\n",
+				__func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
+}
+
+module_init(msm_ipc_router_hsic_init);
+MODULE_DESCRIPTION("IPC Router HSIC XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index d6a3e03..87880c2 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -55,6 +55,8 @@
 	int ss_reset;
 	void *pil;
 	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
 };
 
 struct msm_ipc_router_smd_xprt_work {
@@ -71,13 +73,14 @@
 	char xprt_name[XPRT_NAME_LEN];
 	uint32_t edge;
 	uint32_t link_id;
+	unsigned xprt_version;
 };
 
 struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
-	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
-	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1, 1},
+	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1, 1},
 };
 
 static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
@@ -95,6 +98,28 @@
 	return -ENODEV;
 }
 
+static int msm_ipc_router_smd_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_version;
+}
+
+static int msm_ipc_router_smd_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_option;
+}
+
 static int msm_ipc_router_smd_remote_write_avail(
 	struct msm_ipc_router_xprt *xprt)
 {
@@ -110,7 +135,6 @@
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
-	int align_sz, align_data = 0;
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
@@ -123,9 +147,7 @@
 	if (!len || pkt->length != len)
 		return -EINVAL;
 
-	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_xprtp->channel,
-				      (len + align_sz))) < 0) {
+	while ((ret = smd_write_start(smd_xprtp->channel, len)) < 0) {
 		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
 		if (smd_xprtp->ss_reset) {
 			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
@@ -143,7 +165,7 @@
 		num_retries++;
 	}
 
-	D("%s: Ready to write\n", __func__);
+	D("%s: Ready to write %d bytes\n", __func__, len);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
@@ -175,30 +197,6 @@
 		  __func__, offset, xprt->name);
 	}
 
-	if (align_sz) {
-		if (smd_write_segment_avail(smd_xprtp->channel) < align_sz)
-			smd_enable_read_intr(smd_xprtp->channel);
-
-		wait_event(smd_xprtp->write_avail_wait_q,
-			((smd_write_segment_avail(smd_xprtp->channel) >=
-			 align_sz) || smd_xprtp->ss_reset));
-		smd_disable_read_intr(smd_xprtp->channel);
-		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
-		if (smd_xprtp->ss_reset) {
-			spin_unlock_irqrestore(
-				&smd_xprtp->ss_reset_lock, flags);
-			pr_err("%s: %s chnl reset\n",
-				__func__, xprt->name);
-			return -ENETRESET;
-		}
-		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
-					flags);
-
-		smd_write_segment(smd_xprtp->channel,
-				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes over %s\n",
-		  __func__, align_sz, xprt->name);
-	}
 	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
@@ -453,6 +451,10 @@
 
 	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
 	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_smd_get_xprt_version;
+	smd_remote_xprt[id].xprt.get_option =
+		msm_ipc_router_smd_get_xprt_option;
 	smd_remote_xprt[id].xprt.read_avail = NULL;
 	smd_remote_xprt[id].xprt.read = NULL;
 	smd_remote_xprt[id].xprt.write_avail =
@@ -468,6 +470,8 @@
 	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
 	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
 	smd_remote_xprt[id].ss_reset = 0;
+	smd_remote_xprt[id].xprt_version = smd_xprt_cfg[id].xprt_version;
+	smd_remote_xprt[id].xprt_option = FRAG_PKT_WRITE_ENABLE;
 
 	smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
 					smd_xprt_cfg[id].edge);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index ea27c71..bdda546 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -131,12 +131,15 @@
 	int i, copied, first = 1;
 	int data_size = 0, request_size, offset;
 	void *data;
+	int last = 0;
+	int align_size;
 
 	for (i = 0; i < num_sect; i++)
 		data_size += msg_sect[i].iov_len;
 
 	if (!data_size)
 		return NULL;
+	align_size = ALIGN_SIZE(data_size);
 
 	msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!msg_head) {
@@ -148,10 +151,14 @@
 	for (copied = 1, i = 0; copied && (i < num_sect); i++) {
 		data_size = msg_sect[i].iov_len;
 		offset = 0;
+		if (i == (num_sect - 1))
+			last = 1;
 		while (offset != msg_sect[i].iov_len) {
 			request_size = data_size;
 			if (first)
 				request_size += IPC_ROUTER_HDR_SIZE;
+			if (last)
+				request_size += align_size;
 
 			msg = alloc_skb(request_size, GFP_KERNEL);
 			if (!msg) {
@@ -161,6 +168,7 @@
 					goto msg_build_failure;
 				}
 				data_size = data_size / 2;
+				last = 0;
 				continue;
 			}
 
@@ -182,6 +190,8 @@
 			skb_queue_tail(msg_head, msg);
 			offset += data_size;
 			data_size = msg_sect[i].iov_len - offset;
+			if (i == (num_sect - 1))
+				last = 1;
 		}
 	}
 	return msg_head;
@@ -196,24 +206,23 @@
 }
 
 static int msm_ipc_router_extract_msg(struct msghdr *m,
-				      struct sk_buff_head *msg_head)
+				      struct rr_packet *pkt)
 {
 	struct sockaddr_msm_ipc *addr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct sk_buff *temp;
 	union rr_control_msg *ctl_msg;
 	int offset = 0, data_len = 0, copy_len;
 
-	if (!m || !msg_head) {
+	if (!m || !pkt) {
 		pr_err("%s: Invalid pointers passed\n", __func__);
 		return -EINVAL;
 	}
 	addr = (struct sockaddr_msm_ipc *)m->msg_name;
 
-	temp = skb_peek(msg_head);
-	hdr = (struct rr_header *)(temp->data);
+	hdr = &(pkt->hdr);
 	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
-		skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+		temp = skb_peek(pkt->pkt_fragment_q);
 		ctl_msg = (union rr_control_msg *)(temp->data);
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -222,7 +231,7 @@
 		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
 		return offset;
 	}
-	if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
 		addr->address.addr.port_addr.node_id = hdr->src_node_id;
@@ -231,8 +240,7 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp, IPC_ROUTER_HDR_SIZE);
-	skb_queue_walk(msg_head, temp) {
+	skb_queue_walk(pkt->pkt_fragment_q, temp) {
 		copy_len = data_len < temp->len ? data_len : temp->len;
 		if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
 				 copy_len)) {
@@ -245,22 +253,6 @@
 	return offset;
 }
 
-static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
-{
-	struct sk_buff *temp;
-
-	if (!msg_head) {
-		pr_err("%s: Invalid msg pointer\n", __func__);
-		return;
-	}
-
-	while (!skb_queue_empty(msg_head)) {
-		temp = skb_dequeue(msg_head);
-		kfree_skb(temp);
-	}
-	kfree(msg_head);
-}
-
 static int msm_ipc_router_create(struct net *net,
 				 struct socket *sock,
 				 int protocol,
@@ -385,8 +377,16 @@
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
-	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
-		ret = total_len;
+	if (ret != total_len) {
+		if (ret < 0) {
+			if (ret != -EAGAIN)
+				pr_err("%s: Send_to failure %d\n",
+							__func__, ret);
+			msm_ipc_router_free_skb(msg);
+		} else if (ret >= 0) {
+			ret = -EFAULT;
+		}
+	}
 
 out_sendmsg:
 	release_sock(sk);
@@ -398,7 +398,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
-	struct sk_buff_head *msg;
+	struct rr_packet *pkt;
 	struct sk_buff *ipc_buf;
 	long timeout;
 	int ret;
@@ -420,18 +420,17 @@
 		return ret;
 	}
 
-	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
-	if (ret <= 0 || !msg) {
+	ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
+	if (ret <= 0 || !pkt) {
 		release_sock(sk);
 		return ret;
 	}
 
-	ret = msm_ipc_router_extract_msg(m, msg);
-	ipc_buf = skb_peek(msg);
+	ret = msm_ipc_router_extract_msg(m, pkt);
+	ipc_buf = skb_peek(pkt->pkt_fragment_q);
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
-	msm_ipc_router_release_msg(msg);
-	msg = NULL;
+	release_pkt(pkt);
 	release_sock(sk);
 	return ret;
 }
@@ -460,7 +459,7 @@
 
 	switch (cmd) {
 	case IPC_ROUTER_IOCTL_GET_VERSION:
-		n = IPC_ROUTER_VERSION;
+		n = IPC_ROUTER_V1;
 		ret = put_user(n, (unsigned int *)arg);
 		break;
 
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 180d277..249a334 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -191,6 +191,9 @@
 	case MSM_SPM_L2_MODE_GDHS:
 		msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
 		break;
+	case MSM_SPM_L2_MODE_PC_NO_RPM:
+		msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
+		break;
 	case MSM_SPM_L2_MODE_RETENTION:
 	case MSM_SPM_L2_MODE_DISABLED:
 		break;
@@ -448,6 +451,7 @@
 	int i;
 	struct lpm_lookup_table l2_mode_lookup[] = {
 		{MSM_SPM_L2_MODE_POWER_COLLAPSE, "l2_cache_pc"},
+		{MSM_SPM_L2_MODE_PC_NO_RPM, "l2_cache_pc_no_rpm"},
 		{MSM_SPM_L2_MODE_GDHS, "l2_cache_gdhs"},
 		{MSM_SPM_L2_MODE_RETENTION, "l2_cache_retention"},
 		{MSM_SPM_L2_MODE_DISABLED, "l2_cache_active"}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index bc15fe8..8b64653 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1876,7 +1876,7 @@
 	struct msm_bus_bimc_info *binfo;
 	struct msm_bus_bimc_qos_bw qbw;
 	int i;
-	long int bw;
+	int64_t bw;
 	int ports = info->node_info->num_mports;
 	struct msm_bus_bimc_commit *sel_cd =
 		(struct msm_bus_bimc_commit *)sel_cdata;
@@ -1912,11 +1912,11 @@
 			qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
 			qbw.ws = info->node_info->ws;
 			/* Threshold low = 90% of bw */
-			qbw.thl = (90 * bw) / 100;
+			qbw.thl = div_s64((90 * bw), 100);
 			/* Threshold medium = bw */
 			qbw.thm = bw;
 			/* Threshold high = 10% more than bw */
-			qbw.thh = (110 * bw) / 100;
+			qbw.thh = div_s64((110 * bw), 100);
 			/* Check if info is a shared master.
 			 * If it is, mark it dirty
 			 * If it isn't, then set QOS Bandwidth
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/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index d33c340..8f7b7f2 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -511,7 +511,7 @@
 	struct msm_bus_noc_info *ninfo;
 	struct msm_bus_noc_qos_bw qos_bw;
 	int i, ports;
-	long int bw;
+	int64_t bw;
 	struct msm_bus_noc_commit *sel_cd =
 		(struct msm_bus_noc_commit *)sel_cdata;
 
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index a8fed52..e2ff0f4 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -160,6 +160,10 @@
 		msg_id = ((struct qmi_header *)pend_txn->enc_data)->msg_id;
 		kfree(pend_txn->enc_data);
 		if (ret < 0) {
+			pr_err("%s: Sending transaction %d from port %d failed",
+				__func__, pend_txn->txn_id,
+				((struct msm_ipc_port *)handle->src_port)->
+							this_port.port_id);
 			if (pend_txn->type == QMI_ASYNC_TXN) {
 				pend_txn->resp_cb(pend_txn->handle,
 						msg_id, pend_txn->resp,
@@ -171,10 +175,6 @@
 				pend_txn->send_stat = ret;
 				wake_up(&pend_txn->wait_q);
 			}
-			pr_err("%s: Sending transaction %d from port %d failed",
-				__func__, pend_txn->txn_id,
-				((struct msm_ipc_port *)handle->src_port)->
-							this_port.port_id);
 		} else {
 			list_del(&pend_txn->list);
 			list_add_tail(&pend_txn->list, &handle->txn_list);
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 153864d..c186a5e 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -43,6 +43,8 @@
 	unsigned int num_macros;
 	struct ocmem_hw_macro *macro;
 	struct msm_rpm_request *rpm_req;
+	unsigned long macro_size;
+	unsigned long region_size;
 	unsigned r_state;
 };
 
@@ -69,6 +71,9 @@
 #define NUM_MACROS_MASK (0x3F << 8)
 #define NUM_MACROS_SHIFT (8)
 
+#define LAST_REGN_HALFSIZE_MASK (0x1 << 16)
+#define LAST_REGN_HALFSIZE_SHIFT (16)
+
 #define INTERLEAVING_MASK (0x1 << 17)
 #define INTERLEAVING_SHIFT (17)
 
@@ -198,7 +203,13 @@
 
 	return state;
 }
+
 #ifndef CONFIG_MSM_OCMEM_POWER_DISABLE
+static struct ocmem_hw_region *get_ocmem_region(unsigned region_num)
+{
+	return &region_ctrl[region_num];
+}
+
 static int commit_region_staging(unsigned region_num, unsigned start_m,
 				unsigned new_state)
 {
@@ -933,6 +944,7 @@
 	unsigned start_m = num_banks;
 	unsigned end_m = num_banks;
 	unsigned long region_offset = 0;
+	struct ocmem_hw_region *region;
 	int rc = 0;
 
 	if (offset < 0)
@@ -966,6 +978,7 @@
 
 	for (i = region_start; i <= region_end; i++) {
 
+		region = get_ocmem_region(i);
 		curr_state = read_region_state(i);
 
 		switch (curr_state) {
@@ -981,14 +994,14 @@
 			break;
 		}
 
-		if (len >= region_size) {
+		if (len >= region->region_size) {
 			pr_debug("switch: entire region (%d)\n", i);
 			start_m = 0;
 			end_m = num_banks;
 		} else {
-			region_offset = offset - (i * region_size);
-			start_m = region_offset / macro_size;
-			end_m = (region_offset + len - 1) / macro_size;
+			region_offset = offset - (i * region->region_size);
+			start_m = region_offset / region->macro_size;
+			end_m = (region_offset + len - 1) / region->macro_size;
 			pr_debug("switch: macro (%u to %u)\n", start_m, end_m);
 		}
 
@@ -1002,7 +1015,7 @@
 		aggregate_region_state(i);
 		if (rpm_power_control)
 			commit_region_state(i);
-		len -= region_size;
+		len -= region->region_size;
 
 		/* If we voted ON/retain the banks must never be OFF */
 		if (new_state != REGION_DEFAULT_OFF) {
@@ -1123,6 +1136,7 @@
 	struct device   *dev = &pdev->dev;
 	struct ocmem_plat_data *pdata = NULL;
 	unsigned hw_ver;
+	bool last_region_halfsize;
 	bool interleaved;
 	unsigned i, j, k;
 	unsigned rsc_type = 0;
@@ -1146,6 +1160,9 @@
 		goto hw_not_supported;
 	}
 
+	last_region_halfsize = (hw_ver & LAST_REGN_HALFSIZE_MASK) >>
+					LAST_REGN_HALFSIZE_SHIFT;
+
 	interleaved = (hw_ver & INTERLEAVING_MASK) >> INTERLEAVING_SHIFT;
 
 	num_regions = pdata->nr_regions;
@@ -1179,6 +1196,14 @@
 		region->r_state = REGION_DEFAULT_OFF;
 		region->num_macros = num_banks;
 
+		if (last_region_halfsize && i == (num_regions - 1)) {
+			region->macro_size = macro_size / 2;
+			region->region_size = region_size / 2;
+		} else {
+			region->macro_size = macro_size;
+			region->region_size = region_size;
+		}
+
 		region->macro = devm_kzalloc(dev,
 					sizeof(struct ocmem_hw_macro) *
 						num_banks, GFP_KERNEL);
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 a9a6942..322061d 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -378,9 +378,7 @@
 {
 	struct lpass_data *drv = subsys_to_drv(dev_id);
 
-	disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
 	schedule_work(&drv->work);
-
 	return IRQ_HANDLED;
 }
 
@@ -496,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);
@@ -509,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 da5e67a..00b0b3b 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -481,6 +481,10 @@
 	bool collapsed = 0;
 	int ret;
 	bool save_cpu_regs = !cpu || from_idle;
+	unsigned int saved_gic_cpu_ctrl;
+
+	saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+	mb();
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: notify_rpm %d\n",
@@ -503,6 +507,9 @@
 	if (from_idle && msm_pm_pc_reset_timer)
 		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
 
+#ifdef CONFIG_VFP
+	vfp_pm_suspend();
+#endif
 	collapsed = save_cpu_regs ? msm_pm_collapse() : msm_pm_pc_hotplug();
 
 	if (from_idle && msm_pm_pc_reset_timer)
@@ -511,7 +518,14 @@
 	msm_pm_boot_config_after_pc(cpu);
 
 	if (collapsed) {
+#ifdef CONFIG_VFP
+		vfp_pm_resume();
+#endif
 		cpu_init();
+		writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
+		writel_relaxed(saved_gic_cpu_ctrl,
+				MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+		mb();
 		local_fiq_enable();
 	}
 
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 1f04e76..d32dc4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * amrnb audio decoder device
  *
- * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 743eee2..0eca74d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -2,7 +2,7 @@
  *
  * amrnb encoder device
  *
- * Copyright (c) 2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009, 2011-2013 The Linux Foundation. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5/audio_in.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -742,6 +742,7 @@
 	MM_DBG("\n");
 	if (cmd == AUDIO_GET_STATS) {
 		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
 		stats.byte_count = atomic_read(&audio->in_bytes);
 		stats.sample_count = atomic_read(&audio->in_samples);
 		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 83a2633..cfda4b9 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
  *
  * qcelp audio input device
  *
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -732,6 +732,7 @@
 	MM_DBG("\n");
 	if (cmd == AUDIO_GET_STATS) {
 		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
 		stats.byte_count = atomic_read(&audio->in_bytes);
 		stats.sample_count = atomic_read(&audio->in_samples);
 		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index ae63f0d..f7295b7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -644,6 +644,7 @@
 
 	if (cmd == AUDIO_GET_STATS) {
 		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
 		mutex_lock(&audio->dsp_lock);
 		stats.byte_count = audio->byte_count;
 		stats.sample_count = audio->frame_count;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index 8e66939..cb3c3ea 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -503,6 +503,7 @@
 
 	if (cmd == AUDIO_GET_STATS) {
 		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
 		stats.byte_count = atomic_read(&audio->in_bytes);
 		stats.sample_count = atomic_read(&audio->in_samples);
 		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 0f8956f..37a6726 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -778,6 +778,7 @@
 	MM_DBG("\n");
 	if (cmd == AUDIO_GET_STATS) {
 		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
 		stats.byte_count = atomic_read(&audio->in_bytes);
 		stats.sample_count = atomic_read(&audio->in_samples);
 		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c
index c6bddb8..288e1dc 100644
--- a/arch/arm/mach-msm/qdsp6/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6/pcm_in.c
@@ -141,6 +141,7 @@
 	}
 	case AUDIO_GET_CONFIG: {
 		struct msm_audio_config config;
+		memset(&config, 0, sizeof(config));
 		config.buffer_size = pcm->buffer_size;
 		config.buffer_count = 2;
 		config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/qdsp6v2/aac_in.c b/arch/arm/mach-msm/qdsp6v2/aac_in.c
index 5e959b5..0741538 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
@@ -125,6 +125,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/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index 0506e7e..0bd2010 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -54,25 +54,36 @@
 	int rc = 0;
 	u32 adsp_state;
 
+	if (!pdev) {
+		dev_err(&pdev->dev, "%s: Platform device null \n", __func__);
+		goto fail;
+	}
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev,
+			"%s: Device tree information missing \n", __func__);
+		goto fail;
+	}
+
 	rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
 	if (rc) {
 		dev_err(&pdev->dev,
 			"%s: ADSP state = %x\n", __func__, adsp_state);
-		return;
+		goto fail;
 	}
 
 	if (adsp_state == APR_SUBSYS_DOWN) {
-		if (pdev) {
-			priv = platform_get_drvdata(pdev);
-		} else {
-			pr_err("%s: Private data get failed\n", __func__);
+		priv = platform_get_drvdata(pdev);
+		if (!priv) {
+			dev_err(&pdev->dev,
+				" %s: Private data get failed\n", __func__);
 			goto fail;
 		}
 
 
 		priv->pil_h = subsystem_get("adsp");
 		if (IS_ERR(priv->pil_h)) {
-			pr_err("%s: pil get failed,\n",
+			dev_err(&pdev->dev, "%s: pil get failed,\n",
 				__func__);
 			goto fail;
 		}
@@ -86,11 +97,11 @@
 	}
 
 
-	pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+	dev_info(&pdev->dev, "%s: Q6/ADSP image is loaded\n", __func__);
 	return;
 fail:
 
-	pr_err("%s: Q6/ADSP image loading failed\n", __func__);
+	dev_err(&pdev->dev, "%s: Q6/ADSP image loading failed\n", __func__);
 	return;
 }
 
@@ -118,9 +129,9 @@
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
-		pr_err("%s: memory alloc failed\n", __func__);
+		dev_err(&pdev->dev, "%s: memory alloc failed\n", __func__);
 		ret = -ENOMEM;
-		goto error_return;
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, priv);
@@ -131,7 +142,7 @@
 				sizeof(*(priv->attr_group)),
 				GFP_KERNEL);
 	if (!priv->attr_group) {
-		pr_err("%s: malloc attr_group failed\n",
+		dev_err(&pdev->dev, "%s: malloc attr_group failed\n",
 						__func__);
 		ret = -ENOMEM;
 		goto error_return;
@@ -141,7 +152,7 @@
 
 	priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
 	if (!priv->boot_adsp_obj) {
-		pr_err("%s: sysfs create and add failed\n",
+		dev_err(&pdev->dev, "%s: sysfs create and add failed\n",
 						__func__);
 		ret = -ENOMEM;
 		goto error_return;
@@ -149,7 +160,7 @@
 
 	ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
 	if (ret) {
-		pr_err("%s: sysfs create group failed %d\n", \
+		dev_err(&pdev->dev, "%s: sysfs create group failed %d\n", \
 							__func__, ret);
 		goto error_return;
 	}
@@ -195,7 +206,7 @@
 {
 	int ret = adsp_loader_init_sysfs(pdev);
 	if (ret != 0) {
-		pr_err("%s: Error in initing sysfs\n", __func__);
+		dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__);
 		return ret;
 	}
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index b5ccc31..a13100b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -887,7 +887,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/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 33bbac0..5355de1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -197,6 +197,7 @@
 
 	if (cmd == AUDIO_GET_STATS) {
 		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
 		stats.byte_count = atomic_read(&audio->in_bytes);
 		stats.sample_count = atomic_read(&audio->in_samples);
 		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index d34bdf2..110ab87 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -57,7 +57,7 @@
 
 #define SMD_VERSION 0x00020000
 #define SMSM_SNAPSHOT_CNT 64
-#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
+#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4 + sizeof(uint64_t))
 #define RSPIN_INIT_WAIT_MS 1000
 #define SMD_FIFO_FULL_RESERVE 4
 
@@ -144,49 +144,65 @@
 	SMSM_APPS_DEM_I = 3,
 };
 
-int msm_smd_debug_mask = MSM_SMx_POWER_INFO | MSM_SMD_INFO;
+int msm_smd_debug_mask = MSM_SMD_POWER_INFO | MSM_SMD_INFO |
+							MSM_SMSM_POWER_INFO;
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 void *smd_log_ctx;
+void *smsm_log_ctx;
 #define NUM_LOG_PAGES 4
 
-#define IPC_LOG(level, x...) do { \
+#define IPC_LOG_SMD(level, x...) do { \
 	if (smd_log_ctx) \
 		ipc_log_string(smd_log_ctx, x); \
 	else \
 		printk(level x); \
 	} while (0)
 
+#define IPC_LOG_SMSM(level, x...) do { \
+	if (smsm_log_ctx) \
+		ipc_log_string(smsm_log_ctx, x); \
+	else \
+		printk(level x); \
+	} while (0)
+
 #if defined(CONFIG_MSM_SMD_DEBUG)
 #define SMD_DBG(x...) do {				\
 		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
-			IPC_LOG(KERN_DEBUG, x);		\
+			IPC_LOG_SMD(KERN_DEBUG, x);	\
 	} while (0)
 
 #define SMSM_DBG(x...) do {					\
 		if (msm_smd_debug_mask & MSM_SMSM_DEBUG)	\
-			IPC_LOG(KERN_DEBUG, x);		\
+			IPC_LOG_SMSM(KERN_DEBUG, x);		\
 	} while (0)
 
 #define SMD_INFO(x...) do {			 	\
 		if (msm_smd_debug_mask & MSM_SMD_INFO)	\
-			IPC_LOG(KERN_INFO, x);		\
+			IPC_LOG_SMD(KERN_INFO, x);	\
 	} while (0)
 
 #define SMSM_INFO(x...) do {				\
 		if (msm_smd_debug_mask & MSM_SMSM_INFO) \
-			IPC_LOG(KERN_INFO, x);		\
+			IPC_LOG_SMSM(KERN_INFO, x);	\
 	} while (0)
-#define SMx_POWER_INFO(x...) do {				\
-		if (msm_smd_debug_mask & MSM_SMx_POWER_INFO) \
-			IPC_LOG(KERN_INFO, x);		\
+
+#define SMD_POWER_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_POWER_INFO)	\
+			IPC_LOG_SMD(KERN_INFO, x);		\
+	} while (0)
+
+#define SMSM_POWER_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMSM_POWER_INFO)	\
+			IPC_LOG_SMSM(KERN_INFO, x);		\
 	} while (0)
 #else
 #define SMD_DBG(x...) do { } while (0)
 #define SMSM_DBG(x...) do { } while (0)
 #define SMD_INFO(x...) do { } while (0)
 #define SMSM_INFO(x...) do { } while (0)
-#define SMx_POWER_INFO(x...) do { } while (0)
+#define SMD_POWER_INFO(x...) do { } while (0)
+#define SMSM_POWER_INFO(x...) do { } while (0)
 #endif
 
 /**
@@ -200,8 +216,6 @@
 #define OVERFLOW_ADD_UNSIGNED(type, a, b) \
 	(((type)~0 - (a)) < (b) ? true : false)
 
-static unsigned last_heap_free = 0xffffffff;
-
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr);
 #ifndef INT_ADSP_A11_SMSM
@@ -223,6 +237,8 @@
 static int smd_stream_write_avail(struct smd_channel *ch);
 static int smd_stream_read_avail(struct smd_channel *ch);
 
+static bool pid_is_on_edge(uint32_t edge_num, unsigned pid);
+
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr)
 {
@@ -237,9 +253,9 @@
 	(void) subsys;
 
 	if (!ch)
-		SMx_POWER_INFO("Apps->%s\n", subsys);
+		SMD_POWER_INFO("Apps->%s\n", subsys);
 	else
-		SMx_POWER_INFO(
+		SMD_POWER_INFO(
 			"Apps->%s ch%d '%s': tx%d/rx%d %dr/%dw : %dr/%dw\n",
 			subsys, ch->n, ch->name,
 			ch->fifo_size -
@@ -322,7 +338,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_MODEM].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "MODEM");
+	SMSM_POWER_INFO("SMSM Apps->%s", "MODEM");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_MODEM].smsm_out_config_count;
@@ -336,7 +352,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_Q6].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "ADSP");
+	SMSM_POWER_INFO("SMSM Apps->%s", "ADSP");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_Q6].smsm_out_config_count;
@@ -350,7 +366,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_DSPS].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "DSPS");
+	SMSM_POWER_INFO("SMSM Apps->%s", "DSPS");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_DSPS].smsm_out_config_count;
@@ -364,7 +380,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_WCNSS].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "WCNSS");
+	SMSM_POWER_INFO("SMSM Apps->%s", "WCNSS");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
@@ -447,13 +463,15 @@
 	char *x;
 	int size;
 
-	x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
+	x = smem_find_to_proc(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG, 0,
+							SMEM_ANY_HOST_FLAG);
 	if (x != 0) {
 		x[SZ_DIAG_ERR_MSG - 1] = 0;
 		SMD_INFO("smem: DIAG '%s'\n", x);
 	}
 
-	x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
+	x = smem_get_entry_to_proc(SMEM_ERR_CRASH_LOG, &size, 0,
+							SMEM_ANY_HOST_FLAG);
 	if (x != 0) {
 		x[size - 1] = 0;
 		pr_err("smem: CRASH LOG\n'%s'\n", x);
@@ -560,15 +578,17 @@
 static LIST_HEAD(smd_ch_closed_list);
 static LIST_HEAD(smd_ch_closing_list);
 static LIST_HEAD(smd_ch_to_close_list);
-static LIST_HEAD(smd_ch_list_modem);
-static LIST_HEAD(smd_ch_list_dsp);
-static LIST_HEAD(smd_ch_list_dsps);
-static LIST_HEAD(smd_ch_list_wcnss);
-static LIST_HEAD(smd_ch_list_rpm);
 
-/* 2 total supported tables of channels */
-static unsigned char smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS * 2];
-static struct work_struct probe_work;
+struct remote_proc_info {
+	unsigned remote_pid;
+	unsigned free_space;
+	struct work_struct probe_work;
+	struct list_head ch_list;
+	/* 2 total supported tables of channels */
+	unsigned char ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS * 2];
+};
+
+static struct remote_proc_info remote_info[NUM_SMD_SUBSYSTEMS];
 
 static void finalize_channel_close_fn(struct work_struct *work);
 static DECLARE_WORK(finalize_channel_close_work, finalize_channel_close_fn);
@@ -576,7 +596,8 @@
 
 #define PRI_ALLOC_TBL 1
 #define SEC_ALLOC_TBL 2
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id);
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id,
+				struct remote_proc_info *r_info);
 
 static bool smd_edge_inited(int edge)
 {
@@ -594,19 +615,23 @@
  *
  * @shared: pointer to the table array in SMEM
  * @smd_ch_allocated: pointer to an array indicating already allocated channels
- * table_id: identifier for this channel allocation table
+ * @table_id: identifier for this channel allocation table
+ * @num_entries: number of entries in this allocation table
+ * @r_info: pointer to the info structure of the remote proc we care about
  *
  * The smd_probe_lock must be locked by the calling function.  Shared and
  * smd_ch_allocated are assumed to be valid pointers.
  */
 static void scan_alloc_table(struct smd_alloc_elm *shared,
 				char *smd_ch_allocated,
-				int table_id)
+				int table_id,
+				unsigned num_entries,
+				struct remote_proc_info *r_info)
 {
 	unsigned n;
 	uint32_t type;
 
-	for (n = 0; n < SMEM_NUM_SMD_STREAM_CHANNELS; n++) {
+	for (n = 0; n < num_entries; n++) {
 		if (smd_ch_allocated[n])
 			continue;
 
@@ -615,8 +640,8 @@
 		 * involved
 		 */
 		type = SMD_CHANNEL_TYPE(shared[n].type);
-		if (type >= ARRAY_SIZE(edge_to_pids) ||
-				edge_to_pids[type].local_pid != SMD_APPS)
+		if (!pid_is_on_edge(type, SMD_APPS) ||
+				!pid_is_on_edge(type, r_info->remote_pid))
 			continue;
 		if (!shared[n].ref_count)
 			continue;
@@ -625,17 +650,17 @@
 
 		if (!smd_initialized && !smd_edge_inited(type)) {
 			SMD_INFO(
-				"Probe skipping tbl %d, ch %d, edge not inited\n",
-				table_id, n);
+				"Probe skipping proc %d, tbl %d, ch %d, edge not inited\n",
+				r_info->remote_pid, table_id, n);
 			continue;
 		}
 
-		if (!smd_alloc_channel(&shared[n], table_id))
+		if (!smd_alloc_channel(&shared[n], table_id, r_info))
 			smd_ch_allocated[n] = 1;
 		else
 			SMD_INFO(
-				"Probe skipping tbl %d, ch %d, not allocated\n",
-				table_id, n);
+				"Probe skipping proc %d, tbl %d, ch %d, not allocated\n",
+				r_info->remote_pid, table_id, n);
 	}
 }
 
@@ -650,9 +675,13 @@
 static void smd_channel_probe_worker(struct work_struct *work)
 {
 	struct smd_alloc_elm *shared;
+	struct remote_proc_info *r_info;
+	unsigned tbl_size;
 
-	shared = smem_find(ID_CH_ALLOC_TBL,
-				sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+	r_info = container_of(work, struct remote_proc_info, probe_work);
+
+	shared = smem_get_entry_to_proc(ID_CH_ALLOC_TBL, &tbl_size,
+							r_info->remote_pid, 0);
 
 	if (!shared) {
 		pr_err("%s: allocation table not initialized\n", __func__);
@@ -661,71 +690,50 @@
 
 	mutex_lock(&smd_probe_lock);
 
-	scan_alloc_table(shared, smd_ch_allocated, PRI_ALLOC_TBL);
+	scan_alloc_table(shared, r_info->ch_allocated, PRI_ALLOC_TBL,
+						tbl_size / sizeof(*shared),
+						r_info);
 
-	shared = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
-			sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+	shared = smem_get_entry_to_proc(SMEM_CHANNEL_ALLOC_TBL_2, &tbl_size,
+							r_info->remote_pid, 0);
 	if (shared)
 		scan_alloc_table(shared,
-			&(smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]),
-			SEC_ALLOC_TBL);
+			&(r_info->ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]),
+			SEC_ALLOC_TBL,
+			tbl_size / sizeof(*shared),
+			r_info);
 
 	mutex_unlock(&smd_probe_lock);
 }
 
 /**
- * Lookup processor ID and determine if it belongs to the proved edge
- * type.
+ * get_remote_ch() - gathers remote channel info
  *
  * @shared2:   Pointer to v2 shared channel structure
  * @type:      Edge type
  * @pid:       Processor ID of processor on edge
- * @local_ch:  Channel that belongs to processor @pid
- * @remote_ch: Other side of edge contained @pid
+ * @remote_ch:  Channel that belongs to processor @pid
  * @is_word_access_ch: Bool, is this a word aligned access channel
  *
- * Returns 0 for not on edge, 1 for found on edge
+ * @returns:		0 on success, error code on failure
  */
-static int pid_is_on_edge(void *shared2,
+static int get_remote_ch(void *shared2,
 		uint32_t type, uint32_t pid,
-		void **local_ch,
 		void **remote_ch,
 		int is_word_access_ch
 		)
 {
-	int ret = 0;
-	struct edge_to_pid *edge;
-	void *ch0;
-	void *ch1;
+	if (!remote_ch || !shared2 || !pid_is_on_edge(type, pid) ||
+				!pid_is_on_edge(type, SMD_APPS))
+		return -EINVAL;
 
-	*local_ch = 0;
-	*remote_ch = 0;
+	if (is_word_access_ch)
+		*remote_ch =
+			&((struct smd_shared_v2_word_access *)(shared2))->ch1;
+	else
+		*remote_ch = &((struct smd_shared_v2 *)(shared2))->ch1;
 
-	if (!shared2 || (type >= ARRAY_SIZE(edge_to_pids)))
-		return 0;
-
-	if (is_word_access_ch) {
-		ch0 = &((struct smd_shared_v2_word_access *)(shared2))->ch0;
-		ch1 = &((struct smd_shared_v2_word_access *)(shared2))->ch1;
-	} else {
-		ch0 = &((struct smd_shared_v2 *)(shared2))->ch0;
-		ch1 = &((struct smd_shared_v2 *)(shared2))->ch1;
-	}
-
-	edge = &edge_to_pids[type];
-	if (edge->local_pid != edge->remote_pid) {
-		if (pid == edge->local_pid) {
-			*local_ch = ch0;
-			*remote_ch = ch1;
-			ret = 1;
-		} else if (pid == edge->remote_pid) {
-			*local_ch = ch1;
-			*remote_ch = ch0;
-			ret = 1;
-		}
-	}
-
-	return ret;
+	return 0;
 }
 
 /**
@@ -825,13 +833,25 @@
 	}
 }
 
+/**
+ * smd_channel_reset_state() - find channels in an allocation table and set them
+ *				to the specified state
+ *
+ * @shared:	Pointer to the allocation table to scan
+ * @table_id:	ID of the table
+ * @new_state:	New state that channels should be set to
+ * @pid:	Processor ID of the remote processor for the channels
+ * @num_entries: Number of entries in the table
+ *
+ * Scan the indicated table for channels between Apps and @pid.  If a valid
+ * channel is found, set the remote side of the channel to @new_state.
+ */
 static void smd_channel_reset_state(struct smd_alloc_elm *shared, int table_id,
-		unsigned new_state, unsigned pid)
+		unsigned new_state, unsigned pid, unsigned num_entries)
 {
 	unsigned n;
 	void *shared2;
 	uint32_t type;
-	void *local_ch;
 	void *remote_ch;
 	int is_word_access;
 	unsigned base_id;
@@ -848,7 +868,7 @@
 		return;
 	}
 
-	for (n = 0; n < SMD_CHANNELS; n++) {
+	for (n = 0; n < num_entries; n++) {
 		if (!shared[n].ref_count)
 			continue;
 		if (!shared[n].name[0])
@@ -857,45 +877,59 @@
 		type = SMD_CHANNEL_TYPE(shared[n].type);
 		is_word_access = is_word_access_ch(type);
 		if (is_word_access)
-			shared2 = smem_alloc(base_id + n,
-				sizeof(struct smd_shared_v2_word_access));
+			shared2 = smem_find_to_proc(base_id + n,
+				sizeof(struct smd_shared_v2_word_access), pid,
+				0);
 		else
-			shared2 = smem_alloc(base_id + n,
-				sizeof(struct smd_shared_v2));
+			shared2 = smem_find_to_proc(base_id + n,
+				sizeof(struct smd_shared_v2), pid, 0);
 		if (!shared2)
 			continue;
 
-		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch,
-							is_word_access))
-			smd_reset_edge(local_ch, new_state, is_word_access);
-
-		/*
-		 * ModemFW is in the same subsystem as ModemSW, but has
-		 * separate SMD edges that need to be reset.
-		 */
-		if (pid == SMSM_MODEM &&
-				pid_is_on_edge(shared2, type, SMD_MODEM_Q6_FW,
-				 &local_ch, &remote_ch, is_word_access))
-			smd_reset_edge(local_ch, new_state, is_word_access);
+		if (!get_remote_ch(shared2, type, pid,
+					&remote_ch, is_word_access))
+			smd_reset_edge(remote_ch, new_state, is_word_access);
 	}
 }
 
+/**
+ * pid_is_on_edge() - checks to see if the processor with id pid is on the
+ * edge specified by edge_num
+ *
+ * @edge_num:		the number of the edge which is being tested
+ * @pid:		the id of the processor being tested
+ *
+ * @returns:		true if on edge, false otherwise
+ */
+static bool pid_is_on_edge(uint32_t edge_num, unsigned pid)
+{
+	struct edge_to_pid edge;
+
+	if (edge_num >= ARRAY_SIZE(edge_to_pids))
+		return 0;
+
+	edge = edge_to_pids[edge_num];
+	return (edge.local_pid == pid || edge.remote_pid == pid);
+}
 
 void smd_channel_reset(uint32_t restart_pid)
 {
 	struct smd_alloc_elm *shared_pri;
 	struct smd_alloc_elm *shared_sec;
 	unsigned long flags;
+	unsigned pri_size;
+	unsigned sec_size;
 
-	SMx_POWER_INFO("%s: starting reset\n", __func__);
+	SMD_POWER_INFO("%s: starting reset\n", __func__);
 
-	shared_pri = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared_pri) * 64);
+	shared_pri = smem_get_entry_to_proc(ID_CH_ALLOC_TBL, &pri_size,
+								restart_pid, 0);
 	if (!shared_pri) {
 		pr_err("%s: allocation table not initialized\n", __func__);
 		return;
 	}
-	shared_sec = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
-						sizeof(*shared_sec) * 64);
+	shared_sec = smem_get_entry_to_proc(SMEM_CHANNEL_ALLOC_TBL_2, &sec_size,
+								restart_pid, 0);
 
 	/* reset SMSM entry */
 	if (smsm_info.state) {
@@ -920,43 +954,33 @@
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
 	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSING,
-								restart_pid);
+				restart_pid, pri_size / sizeof(*shared_pri));
 	if (shared_sec)
 		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
-						SMD_SS_CLOSING, restart_pid);
+						SMD_SS_CLOSING, restart_pid,
+						sec_size / sizeof(*shared_sec));
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
-	/* notify SMD processors */
 	mb();
 	smd_fake_irq_handler(0);
-	notify_modem_smd(NULL);
-	notify_dsp_smd(NULL);
-	notify_dsps_smd(NULL);
-	notify_wcnss_smd(NULL);
-	notify_rpm_smd(NULL);
 
 	/* change all remote states to CLOSED */
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
 	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSED,
-								restart_pid);
+				restart_pid, pri_size / sizeof(*shared_pri));
 	if (shared_sec)
 		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
-						SMD_SS_CLOSED, restart_pid);
+						SMD_SS_CLOSED, restart_pid,
+						sec_size / sizeof(*shared_sec));
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
-	/* notify SMD processors */
 	mb();
 	smd_fake_irq_handler(0);
-	notify_modem_smd(NULL);
-	notify_dsp_smd(NULL);
-	notify_dsps_smd(NULL);
-	notify_wcnss_smd(NULL);
-	notify_rpm_smd(NULL);
 
-	SMx_POWER_INFO("%s: finished reset\n", __func__);
+	SMD_POWER_INFO("%s: finished reset\n", __func__);
 }
 
 /* how many bytes are available for reading */
@@ -1157,15 +1181,33 @@
 	ch->notify_other_cpu(ch);
 }
 
-static void do_smd_probe(void)
+/**
+ * do_smd_probe() - Look for newly created SMD channels a specific processor
+ *
+ * @remote_pid: remote processor id of the proc that may have created channels
+ */
+static void do_smd_probe(unsigned remote_pid)
 {
-	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
-	if (shared->heap_info.free_offset != last_heap_free) {
-		last_heap_free = shared->heap_info.free_offset;
-		schedule_work(&probe_work);
+	unsigned free_space;
+
+	free_space = smem_get_free_space(remote_pid);
+	if (free_space != remote_info[remote_pid].free_space) {
+		remote_info[remote_pid].free_space = free_space;
+		schedule_work(&remote_info[remote_pid].probe_work);
 	}
 }
 
+/**
+ * do_smd_probe() - Look for newly created SMD channels from any remote proc
+ */
+static void do_smd_probe_all(void)
+{
+	int i;
+
+	for (i = 1; i < NUM_SMD_SUBSYSTEMS; ++i)
+		do_smd_probe(i);
+}
+
 static void smd_state_change(struct smd_channel *ch,
 			     unsigned last, unsigned next)
 {
@@ -1230,7 +1272,7 @@
 	spin_unlock_irqrestore(&smd_lock, flags);
 }
 
-static void handle_smd_irq(struct list_head *list,
+static void handle_smd_irq(struct remote_proc_info *r_info,
 		void (*notify)(smd_channel_t *ch))
 {
 	unsigned long flags;
@@ -1238,6 +1280,9 @@
 	unsigned ch_flags;
 	unsigned tmp;
 	unsigned char state_change;
+	struct list_head *list;
+
+	list = &r_info->ch_list;
 
 	spin_lock_irqsave(&smd_lock, flags);
 	list_for_each_entry(ch, list, ch_list) {
@@ -1259,14 +1304,14 @@
 		}
 		tmp = ch->half_ch->get_state(ch->recv);
 		if (tmp != ch->last_state) {
-			SMx_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
+			SMD_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
 					ch->n, ch->name, ch->last_state, tmp);
 			smd_state_change(ch, ch->last_state, tmp);
 			state_change = 1;
 		}
 		if (ch_flags & 0x3) {
 			ch->update_state(ch);
-			SMx_POWER_INFO(
+			SMD_POWER_INFO(
 				"SMD ch%d '%s' Data event 0x%x tx%d/rx%d %dr/%dw : %dr/%dw\n",
 				ch->n, ch->name,
 				ch_flags,
@@ -1281,13 +1326,13 @@
 			ch->notify(ch->priv, SMD_EVENT_DATA);
 		}
 		if (ch_flags & 0x4 && !state_change) {
-			SMx_POWER_INFO("SMD ch%d '%s' State update\n",
+			SMD_POWER_INFO("SMD ch%d '%s' State update\n",
 					ch->n, ch->name);
 			ch->notify(ch->priv, SMD_EVENT_STATUS);
 		}
 	}
 	spin_unlock_irqrestore(&smd_lock, flags);
-	do_smd_probe();
+	do_smd_probe(r_info->remote_pid);
 }
 
 static inline void log_irq(uint32_t subsystem)
@@ -1296,14 +1341,14 @@
 
 	(void) subsys;
 
-	SMx_POWER_INFO("SMD Int %s->Apps\n", subsys);
+	SMD_POWER_INFO("SMD Int %s->Apps\n", subsys);
 }
 
 irqreturn_t smd_modem_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_MODEM);
 	++interrupt_stats[SMD_MODEM].smd_in_count;
-	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
+	handle_smd_irq(&remote_info[SMD_MODEM], notify_modem_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1312,7 +1357,7 @@
 {
 	log_irq(SMD_APPS_QDSP);
 	++interrupt_stats[SMD_Q6].smd_in_count;
-	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
+	handle_smd_irq(&remote_info[SMD_Q6], notify_dsp_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1321,7 +1366,7 @@
 {
 	log_irq(SMD_APPS_DSPS);
 	++interrupt_stats[SMD_DSPS].smd_in_count;
-	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
+	handle_smd_irq(&remote_info[SMD_DSPS], notify_dsps_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1330,7 +1375,7 @@
 {
 	log_irq(SMD_APPS_WCNSS);
 	++interrupt_stats[SMD_WCNSS].smd_in_count;
-	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
+	handle_smd_irq(&remote_info[SMD_WCNSS], notify_wcnss_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1339,18 +1384,18 @@
 {
 	log_irq(SMD_APPS_RPM);
 	++interrupt_stats[SMD_RPM].smd_in_count;
-	handle_smd_irq(&smd_ch_list_rpm, notify_rpm_smd);
+	handle_smd_irq(&remote_info[SMD_RPM], notify_rpm_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
 
 static void smd_fake_irq_handler(unsigned long arg)
 {
-	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
-	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
-	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
-	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
-	handle_smd_irq(&smd_ch_list_rpm, notify_rpm_smd);
+	handle_smd_irq(&remote_info[SMD_MODEM], notify_modem_smd);
+	handle_smd_irq(&remote_info[SMD_Q6], notify_dsp_smd);
+	handle_smd_irq(&remote_info[SMD_DSPS], notify_dsps_smd);
+	handle_smd_irq(&remote_info[SMD_WCNSS], notify_wcnss_smd);
+	handle_smd_irq(&remote_info[SMD_RPM], notify_rpm_smd);
 	handle_smd_irq_closing_list();
 }
 
@@ -1376,32 +1421,32 @@
 	int need_int = 0;
 
 	spin_lock_irqsave(&smd_lock, flags);
-	list_for_each_entry(ch, &smd_ch_list_modem, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_MODEM].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
-	list_for_each_entry(ch, &smd_ch_list_dsp, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_Q6].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
-	list_for_each_entry(ch, &smd_ch_list_dsps, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_DSPS].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
-	list_for_each_entry(ch, &smd_ch_list_wcnss, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_WCNSS].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&smd_lock, flags);
-	do_smd_probe();
+	do_smd_probe_all();
 
 	if (need_int) {
 		SMD_DBG("smd_sleep_exit need interrupt\n");
@@ -1582,12 +1627,14 @@
  * @ch: pointer to the local structure for this channel
  * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
  *		second table, etc
+ * @r_info: pointer to the info structure of the remote proc for this channel
  * @returns: -EINVAL for failure; 0 for success
  *
  * ch must point to an allocated instance of struct smd_channel that is zeroed
  * out, and has the n and type members already initialized to the correct values
  */
-static int smd_alloc_v2(struct smd_channel *ch, int table_id)
+static int smd_alloc_v2(struct smd_channel *ch, int table_id,
+						struct remote_proc_info *r_info)
 {
 	void *buffer;
 	unsigned buffer_sz;
@@ -1610,7 +1657,8 @@
 
 	if (is_word_access_ch(ch->type)) {
 		struct smd_shared_v2_word_access *shared2;
-		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
+		shared2 = smem_alloc_to_proc(base_id + ch->n, sizeof(*shared2),
+							r_info->remote_pid, 0);
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1619,7 +1667,8 @@
 		ch->recv = &shared2->ch1;
 	} else {
 		struct smd_shared_v2 *shared2;
-		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
+		shared2 = smem_alloc_to_proc(base_id + ch->n, sizeof(*shared2),
+							r_info->remote_pid, 0);
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1629,7 +1678,8 @@
 	}
 	ch->half_ch = get_half_ch_funcs(ch->type);
 
-	buffer = smem_get_entry(fifo_id + ch->n, &buffer_sz);
+	buffer = smem_get_entry_to_proc(fifo_id + ch->n, &buffer_sz,
+							r_info->remote_pid, 0);
 	if (!buffer) {
 		SMD_INFO("smem_get_entry failed\n");
 		return -EINVAL;
@@ -1654,7 +1704,8 @@
 }
 
 #else /* define v1 for older targets */
-static int smd_alloc_v2(struct smd_channel *ch, int table_id)
+static int smd_alloc_v2(struct smd_channel *ch, int table_id,
+						struct remote_proc_info *r_info)
 {
 	return -EINVAL;
 }
@@ -1662,7 +1713,8 @@
 static int smd_alloc_v1(struct smd_channel *ch)
 {
 	struct smd_shared_v1 *shared1;
-	shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1));
+	shared1 = smem_alloc_to_proc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1),
+							0, SMEM_ANY_HOST_FLAG);
 	if (!shared1) {
 		pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n);
 		return -EINVAL;
@@ -1685,9 +1737,11 @@
  * @alloc_elm: the allocation element stored in SMEM for this channel
  * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
  *		seconds table, etc
+ * @r_info: pointer to the info structure of the remote proc for this channel
  * @returns: -1 for failure; 0 for success
  */
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id)
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id,
+				struct remote_proc_info *r_info)
 {
 	struct smd_channel *ch;
 
@@ -1699,7 +1753,7 @@
 	ch->n = alloc_elm->cid;
 	ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);
 
-	if (smd_alloc_v2(ch, table_id) && smd_alloc_v1(ch)) {
+	if (smd_alloc_v2(ch, table_id, r_info) && smd_alloc_v1(ch)) {
 		kfree(ch);
 		return -1;
 	}
@@ -1922,18 +1976,11 @@
 	SMD_DBG("smd_open: opening '%s'\n", ch->name);
 
 	spin_lock_irqsave(&smd_lock, flags);
-	if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_MODEM)
-		list_add(&ch->ch_list, &smd_ch_list_modem);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_QDSP)
-		list_add(&ch->ch_list, &smd_ch_list_dsp);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_DSPS)
-		list_add(&ch->ch_list, &smd_ch_list_dsps);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_WCNSS)
-		list_add(&ch->ch_list, &smd_ch_list_wcnss);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_RPM)
-		list_add(&ch->ch_list, &smd_ch_list_rpm);
-	else
+	if (unlikely(ch->type == SMD_LOOPBACK_TYPE))
 		list_add(&ch->ch_list, &smd_ch_list_loopback);
+	else
+		list_add(&ch->ch_list,
+		       &remote_info[edge_to_pids[ch->type].remote_pid].ch_list);
 
 	SMD_DBG("%s: opening ch %d\n", __func__, ch->n);
 
@@ -2232,11 +2279,11 @@
 		return -ENODEV;
 
 	if (mask) {
-		SMx_POWER_INFO("SMD Masking interrupts from %s\n",
+		SMD_POWER_INFO("SMD Masking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
 		irq_chip->irq_mask(irq_data);
 	} else {
-		SMx_POWER_INFO("SMD Unmasking interrupts from %s\n",
+		SMD_POWER_INFO("SMD Unmasking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
 		irq_chip->irq_unmask(irq_data);
 	}
@@ -2405,8 +2452,9 @@
 	}
 	remote_spin_unlock_irqrestore(remote_spinlock, flags);
 
-	smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
-				sizeof(struct smsm_size_info_type));
+	smsm_size_info = smem_alloc_to_proc(SMEM_SMSM_SIZE_INFO,
+				sizeof(struct smsm_size_info_type), 0,
+				SMEM_ANY_HOST_FLAG);
 	if (smsm_size_info) {
 		SMSM_NUM_ENTRIES = smsm_size_info->num_entries;
 		SMSM_NUM_HOSTS = smsm_size_info->num_hosts;
@@ -2423,9 +2471,10 @@
 			"smsm_snapshot");
 
 	if (!smsm_info.state) {
-		smsm_info.state = smem_alloc2(ID_SHARED_STATE,
-					      SMSM_NUM_ENTRIES *
-					      sizeof(uint32_t));
+		smsm_info.state = smem_alloc2_to_proc(ID_SHARED_STATE,
+						SMSM_NUM_ENTRIES *
+						sizeof(uint32_t), 0,
+						SMEM_ANY_HOST_FLAG);
 
 		if (smsm_info.state) {
 			__raw_writel(0, SMSM_STATE_ADDR(SMSM_APPS_STATE));
@@ -2436,10 +2485,12 @@
 	}
 
 	if (!smsm_info.intr_mask) {
-		smsm_info.intr_mask = smem_alloc2(SMEM_SMSM_CPU_INTR_MASK,
-						  SMSM_NUM_ENTRIES *
-						  SMSM_NUM_HOSTS *
-						  sizeof(uint32_t));
+		smsm_info.intr_mask = smem_alloc2_to_proc(
+						SMEM_SMSM_CPU_INTR_MASK,
+						SMSM_NUM_ENTRIES *
+						SMSM_NUM_HOSTS *
+						sizeof(uint32_t), 0,
+						SMEM_ANY_HOST_FLAG);
 
 		if (smsm_info.intr_mask) {
 			for (i = 0; i < SMSM_NUM_ENTRIES; i++)
@@ -2454,9 +2505,10 @@
 	}
 
 	if (!smsm_info.intr_mux)
-		smsm_info.intr_mux = smem_alloc2(SMEM_SMD_SMSM_INTR_MUX,
-						 SMSM_NUM_INTR_MUX *
-						 sizeof(uint32_t));
+		smsm_info.intr_mux = smem_alloc2_to_proc(SMEM_SMD_SMSM_INTR_MUX,
+							SMSM_NUM_INTR_MUX *
+							sizeof(uint32_t), 0,
+							SMEM_ANY_HOST_FLAG);
 
 	i = smsm_cb_init();
 	if (i)
@@ -2509,7 +2561,9 @@
 	uint32_t new_state;
 	unsigned long flags;
 	int ret;
+	uint64_t timestamp;
 
+	timestamp = sched_clock();
 	ret = kfifo_avail(&smsm_snapshot_fifo);
 	if (ret < SMSM_SNAPSHOT_SIZE) {
 		pr_err("%s: SMSM snapshot full %d\n", __func__, ret);
@@ -2532,7 +2586,7 @@
 	if (use_wakelock) {
 		spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
 		if (smsm_snapshot_count == 0) {
-			SMx_POWER_INFO("SMSM snapshot wake lock\n");
+			SMSM_POWER_INFO("SMSM snapshot wake lock\n");
 			wake_lock(&smsm_snapshot_wakelock);
 		}
 		++smsm_snapshot_count;
@@ -2551,6 +2605,12 @@
 		}
 	}
 
+	ret = kfifo_in(&smsm_snapshot_fifo, &timestamp, sizeof(timestamp));
+	if (ret != sizeof(timestamp)) {
+		pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+		goto restore_snapshot_count;
+	}
+
 	/* queue wakelock usage flag */
 	ret = kfifo_in(&smsm_snapshot_fifo,
 			&use_wakelock, sizeof(use_wakelock));
@@ -2568,7 +2628,7 @@
 		if (smsm_snapshot_count) {
 			--smsm_snapshot_count;
 			if (smsm_snapshot_count == 0) {
-				SMx_POWER_INFO("SMSM snapshot wake unlock\n");
+				SMSM_POWER_INFO("SMSM snapshot wake unlock\n");
 				wake_unlock(&smsm_snapshot_wakelock);
 			}
 		} else {
@@ -2651,7 +2711,6 @@
 		if (old_apps != apps) {
 			SMSM_DBG("<SM %08x NOTIFY>\n", apps);
 			__raw_writel(apps, SMSM_STATE_ADDR(SMSM_APPS_STATE));
-			do_smd_probe();
 			notify_other_smsm(SMSM_APPS_STATE, (old_apps ^ apps));
 		}
 
@@ -2663,28 +2722,28 @@
 
 irqreturn_t smsm_modem_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int Modem->Apps\n");
+	SMSM_POWER_INFO("SMSM Int Modem->Apps\n");
 	++interrupt_stats[SMD_MODEM].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
 irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
+	SMSM_POWER_INFO("SMSM Int LPASS->Apps\n");
 	++interrupt_stats[SMD_Q6].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
 irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
+	SMSM_POWER_INFO("SMSM Int DSPS->Apps\n");
 	++interrupt_stats[SMD_DSPS].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
 irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
+	SMSM_POWER_INFO("SMSM Int WCNSS->Apps\n");
 	++interrupt_stats[SMD_WCNSS].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
@@ -2774,7 +2833,7 @@
 	old_state = __raw_readl(SMSM_STATE_ADDR(smsm_entry));
 	new_state = (old_state & ~clear_mask) | set_mask;
 	__raw_writel(new_state, SMSM_STATE_ADDR(smsm_entry));
-	SMx_POWER_INFO("%s %d:%08x->%08x", __func__, smsm_entry,
+	SMSM_POWER_INFO("%s %d:%08x->%08x", __func__, smsm_entry,
 			old_state, new_state);
 	notify_other_smsm(SMSM_APPS_STATE, (old_state ^ new_state));
 
@@ -2818,8 +2877,12 @@
 	uint32_t use_wakelock;
 	int ret;
 	unsigned long flags;
+	uint64_t t_snapshot;
+	uint64_t t_start;
+	unsigned long nanosec_rem;
 
 	while (kfifo_len(&smsm_snapshot_fifo) >= SMSM_SNAPSHOT_SIZE) {
+		t_start = sched_clock();
 		mutex_lock(&smsm_lock);
 		for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
 			state_info = &smsm_states[n];
@@ -2835,7 +2898,7 @@
 
 			state_changes = state_info->last_value ^ new_state;
 			if (state_changes) {
-				SMx_POWER_INFO("SMSM Change %d: %08x->%08x\n",
+				SMSM_POWER_INFO("SMSM Change %d: %08x->%08x\n",
 						n, state_info->last_value,
 						new_state);
 				list_for_each_entry(cb_info,
@@ -2850,6 +2913,15 @@
 			}
 		}
 
+		ret = kfifo_out(&smsm_snapshot_fifo, &t_snapshot,
+				sizeof(t_snapshot));
+		if (ret != sizeof(t_snapshot)) {
+			pr_err("%s: snapshot underflow %d\n",
+				__func__, ret);
+			mutex_unlock(&smsm_lock);
+			return;
+		}
+
 		/* read wakelock flag */
 		ret = kfifo_out(&smsm_snapshot_fifo, &use_wakelock,
 				sizeof(use_wakelock));
@@ -2866,7 +2938,7 @@
 			if (smsm_snapshot_count) {
 				--smsm_snapshot_count;
 				if (smsm_snapshot_count == 0) {
-					SMx_POWER_INFO("SMSM snapshot"
+					SMSM_POWER_INFO("SMSM snapshot"
 						   " wake unlock\n");
 					wake_unlock(&smsm_snapshot_wakelock);
 				}
@@ -2877,6 +2949,12 @@
 			spin_unlock_irqrestore(&smsm_snapshot_count_lock,
 					flags);
 		}
+
+		t_start = t_start - t_snapshot;
+		nanosec_rem = do_div(t_start, 1000000000U);
+		SMSM_POWER_INFO(
+			"SMSM snapshot queue response time %6u.%09lu s\n",
+			(unsigned)t_start, nanosec_rem);
 	}
 }
 
@@ -3087,18 +3165,22 @@
  * smd_post_init() - SMD post initialization
  * @is_leagcy:	1 for Leagcy/platform device init sequence
  *		0 for device tree init sequence
+ * @remote_pid: remote pid that has been initialized.  Ignored when is_legacy=1
  *
  * This function is used by the legacy and device tree initialization
  * to complete the SMD init sequence.
  */
-void smd_post_init(bool is_legacy)
+void smd_post_init(bool is_legacy, unsigned remote_pid)
 {
+	int i;
+
 	if (is_legacy) {
 		smd_initialized = 1;
 		smd_alloc_loopback_channel();
-		tasklet_schedule(&smd_fake_irq_tasklet);
+		for (i = 1; i < NUM_SMD_SUBSYSTEMS; ++i)
+			schedule_work(&remote_info[i].probe_work);
 	} else {
-		schedule_work(&probe_work);
+		schedule_work(&remote_info[remote_pid].probe_work);
 	}
 }
 
@@ -3235,19 +3317,31 @@
 {
 	static bool registered;
 	int rc;
+	int i;
 
 	if (registered)
 		return 0;
 
 	smd_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smd");
 	if (!smd_log_ctx) {
-		pr_err("%s: unable to create logging context\n", __func__);
+		pr_err("%s: unable to create SMD logging context\n", __func__);
+		msm_smd_debug_mask = 0;
+	}
+
+	smsm_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smsm");
+	if (!smsm_log_ctx) {
+		pr_err("%s: unable to create SMSM logging context\n", __func__);
 		msm_smd_debug_mask = 0;
 	}
 
 	registered = true;
 
-	INIT_WORK(&probe_work, smd_channel_probe_worker);
+	for (i = 0; i < NUM_SMD_SUBSYSTEMS; ++i) {
+		remote_info[i].remote_pid = i;
+		remote_info[i].free_space = UINT_MAX;
+		INIT_WORK(&remote_info[i].probe_work, smd_channel_probe_worker);
+		INIT_LIST_HEAD(&remote_info[i].ch_list);
+	}
 
 	channel_close_wq = create_singlethread_workqueue("smd_channel_close");
 	if (IS_ERR(channel_close_wq)) {
diff --git a/arch/arm/mach-msm/smd_init_dt.c b/arch/arm/mach-msm/smd_init_dt.c
index d888a72..640656c 100644
--- a/arch/arm/mach-msm/smd_init_dt.c
+++ b/arch/arm/mach-msm/smd_init_dt.c
@@ -259,7 +259,7 @@
 		smd_set_edge_subsys_name(edge, pilstr);
 
 	smd_set_edge_initialized(edge);
-	smd_post_init(0);
+	smd_post_init(0, remote_pid);
 	return 0;
 
 missing_key:
diff --git a/arch/arm/mach-msm/smd_init_plat.c b/arch/arm/mach-msm/smd_init_plat.c
index c6f6cd9..c58b150 100644
--- a/arch/arm/mach-msm/smd_init_plat.c
+++ b/arch/arm/mach-msm/smd_init_plat.c
@@ -502,7 +502,7 @@
 		pr_err("smd_post_init() failed ret = %d\n", ret);
 		return ret;
 	}
-	smd_post_init(1);
+	smd_post_init(1, 0);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4664197..812a7d6 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -230,7 +230,8 @@
 	MSM_SMSM_DEBUG = 1U << 1,
 	MSM_SMD_INFO = 1U << 2,
 	MSM_SMSM_INFO = 1U << 3,
-	MSM_SMx_POWER_INFO = 1U << 4,
+	MSM_SMD_POWER_INFO = 1U << 4,
+	MSM_SMSM_POWER_INFO = 1U << 5,
 };
 
 struct interrupt_config {
@@ -261,7 +262,7 @@
 extern irqreturn_t smd_rpm_irq_handler(int irq, void *data);
 
 extern int msm_smd_driver_register(void);
-extern void smd_post_init(bool is_legacy);
+extern void smd_post_init(bool is_legacy, unsigned remote_pid);
 extern int smsm_post_init(void);
 
 extern struct interrupt_config *smd_get_intr_config(uint32_t edge);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 1ec2a78..f41240a 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -16,12 +16,14 @@
 #include <linux/moduleparam.h>
 #include <linux/printk.h>
 #include <linux/notifier.h>
+#include <linux/of.h>
 
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_smem.h>
 #include <mach/ramdump.h>
 #include <mach/subsystem_notif.h>
+#include <mach/msm_ipc_logging.h>
 
 #include "smem_private.h"
 
@@ -45,13 +47,29 @@
 	MSM_SMEM_INFO = 1U << 1,
 };
 
-static int msm_smem_debug_mask;
+static int msm_smem_debug_mask = MSM_SMEM_INFO;
 module_param_named(debug_mask, msm_smem_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
+static void *smem_ipc_log_ctx;
+#define NUM_LOG_PAGES 4
 
+#define IPC_LOG(x...) do {                                   \
+		if (smem_ipc_log_ctx)                        \
+			ipc_log_string(smem_ipc_log_ctx, x); \
+	} while (0)
+
+
+#define LOG_ERR(x...) do {  \
+		pr_err(x);  \
+		IPC_LOG(x); \
+	} while (0)
 #define SMEM_DBG(x...) do {                               \
 		if (msm_smem_debug_mask & MSM_SMEM_DEBUG) \
-			pr_debug(x);                      \
+			IPC_LOG(x);                       \
+	} while (0)
+#define SMEM_INFO(x...) do {                             \
+		if (msm_smem_debug_mask & MSM_SMEM_INFO) \
+			IPC_LOG(x);                      \
 	} while (0)
 
 #define SMEM_SPINLOCK_SMEM_ALLOC       "S:3"
@@ -68,6 +86,61 @@
 static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list);
 static DEFINE_MUTEX(smem_module_init_notifier_lock);
 
+/* smem security feature components */
+#define SMEM_TOC_IDENTIFIER 0x434f5424 /* "$TOC" */
+#define SMEM_TOC_MAX_EXCLUSIONS 4
+#define SMEM_PART_HDR_IDENTIFIER 0x54525024 /* "$PRT" */
+#define SMEM_ALLOCATION_CANARY 0xa5a5
+
+struct smem_toc_entry {
+	uint32_t offset;
+	uint32_t size;
+	uint32_t flags;
+	uint16_t host0;
+	uint16_t host1;
+	uint32_t size_cacheline;
+	uint32_t reserved[3];
+	uint32_t exclusion_sizes[SMEM_TOC_MAX_EXCLUSIONS];
+};
+
+struct smem_toc {
+	/* Identifier is a constant, set to SMEM_TOC_IDENTIFIER. */
+	uint32_t identifier;
+	uint32_t version;
+	uint32_t num_entries;
+	uint32_t reserved[5];
+	struct smem_toc_entry entry[];
+};
+
+struct smem_partition_header {
+	/* Identifier is a constant, set to SMEM_PART_HDR_IDENTIFIER. */
+	uint32_t identifier;
+	uint16_t host0;
+	uint16_t host1;
+	uint32_t size;
+	uint32_t offset_free_uncached;
+	uint32_t offset_free_cached;
+	uint32_t reserved[3];
+};
+
+struct smem_partition_allocation_header {
+	/* Canary is a constant, set to SMEM_ALLOCATION_CANARY */
+	uint16_t canary;
+	uint16_t smem_type;
+	uint32_t size; /* includes padding bytes */
+	uint16_t padding_data;
+	uint16_t padding_hdr;
+	uint32_t reserved[1];
+};
+
+struct smem_partition_info {
+	uint32_t partition_num;
+	uint32_t offset;
+	uint32_t size_cacheline;
+};
+
+static struct smem_partition_info partitions[NUM_SMEM_SUBSYSTEMS];
+/* end smem security feature components */
 
 struct restart_notifier_block {
 	unsigned processor;
@@ -128,7 +201,7 @@
 		if (base >= phys_addr && base + offset < phys_addr + size) {
 			if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
-				pr_err("%s: overflow %p %x\n", __func__,
+				SMEM_INFO("%s: overflow %p %x\n", __func__,
 					MSM_SHARED_RAM_BASE, offset);
 				return NULL;
 			}
@@ -147,7 +220,7 @@
 
 		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)smem_areas[i].virt_addr, offset)) {
-			pr_err("%s: overflow %p %x\n", __func__,
+			SMEM_INFO("%s: overflow %p %x\n", __func__,
 				smem_areas[i].virt_addr, offset);
 			return NULL;
 		}
@@ -201,6 +274,22 @@
 EXPORT_SYMBOL(smem_alloc);
 
 /**
+ * smem_alloc_to_proc - Find existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size:     Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags)
+{
+	return smem_find_to_proc(id, size, to_proc, flags);
+}
+EXPORT_SYMBOL(smem_alloc_to_proc);
+
+/**
  * __smem_get_entry - Get pointer and size of existing SMEM item
  *
  * @id:              ID of SMEM item
@@ -246,6 +335,138 @@
 	return ret;
 }
 
+/**
+ * __smem_get_entry_to_proc - Get pointer and size of existing SMEM item with
+ *                   security support
+ *
+ * @id:              ID of SMEM item
+ * @size:            Pointer to size variable for storing the result
+ * @to_proc:         SMEM host that shares the item with apps
+ * @flags:           Item attribute flags
+ * @skip_init_check: True means do not verify that SMEM has been initialized
+ * @use_rspinlock:   True to use the remote spinlock
+ * @returns:         Pointer to SMEM item or NULL if it doesn't exist
+ */
+static void *__smem_get_entry_to_proc(unsigned id,
+					unsigned *size,
+					unsigned to_proc,
+					unsigned flags,
+					bool skip_init_check,
+					bool use_rspinlock)
+{
+	struct smem_partition_header *hdr;
+	unsigned long lflags = 0;
+	void *item = NULL;
+	struct smem_partition_allocation_header *alloc_hdr;
+	uint32_t partition_num;
+	uint32_t a_hdr_size;
+	int rc;
+
+	SMEM_DBG("%s(%u, %u, %u, %u, %d, %d)\n", __func__, id, *size, to_proc,
+					flags, skip_init_check, use_rspinlock);
+
+	if (!skip_init_check && !smem_initialized_check())
+		return NULL;
+
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %d\n", __func__, id);
+		return NULL;
+	}
+
+	if (!(flags & SMEM_ANY_HOST_FLAG) && to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("%s: id %u invalid to_proc %d\n", __func__, id,
+								to_proc);
+		return NULL;
+	}
+
+	if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
+		return __smem_get_entry(id, size, skip_init_check,
+								use_rspinlock);
+
+	partition_num = partitions[to_proc].partition_num;
+	hdr = smem_areas[0].virt_addr + partitions[to_proc].offset;
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			SMEM_INFO(
+				"%s: id:%u remote spinlock init failed %d\n",
+						__func__, id, rc);
+			return NULL;
+		}
+	}
+	if (use_rspinlock)
+		remote_spin_lock_irqsave(&remote_spinlock, lflags);
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR(
+			"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								hdr);
+		BUG();
+	}
+
+	if (flags & SMEM_ITEM_CACHED_FLAG) {
+		a_hdr_size = ALIGN(sizeof(*alloc_hdr),
+				partitions[to_proc].size_cacheline);
+		for (alloc_hdr = (void *)(hdr) + hdr->size - a_hdr_size;
+				(void *)(alloc_hdr) > (void *)(hdr) +
+					hdr->offset_free_cached;
+				alloc_hdr = (void *)(alloc_hdr) -
+						alloc_hdr->size - a_hdr_size) {
+			if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
+				LOG_ERR(
+					"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								alloc_hdr);
+				BUG();
+
+			}
+			if (alloc_hdr->smem_type == id) {
+				/* 8 byte alignment to match legacy */
+				*size = ALIGN(alloc_hdr->size -
+						alloc_hdr->padding_data, 8);
+				item = (void *)(alloc_hdr) - alloc_hdr->size;
+				break;
+			}
+		}
+	} else {
+		for (alloc_hdr = (void *)(hdr) + sizeof(*hdr);
+				(void *)(alloc_hdr) < (void *)(hdr) +
+					hdr->offset_free_uncached;
+				alloc_hdr = (void *)(alloc_hdr) +
+						sizeof(*alloc_hdr) +
+						alloc_hdr->padding_hdr +
+						alloc_hdr->size) {
+			if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
+				LOG_ERR(
+					"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								alloc_hdr);
+				BUG();
+
+			}
+			if (alloc_hdr->smem_type == id) {
+				/* 8 byte alignment to match legacy */
+				*size = ALIGN(alloc_hdr->size -
+						alloc_hdr->padding_data, 8);
+				item = (void *)(alloc_hdr) +
+						sizeof(*alloc_hdr) +
+						alloc_hdr->padding_hdr;
+				break;
+			}
+		}
+	}
+	if (use_rspinlock)
+		remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+
+	return item;
+}
+
 static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
 {
 	unsigned size;
@@ -257,7 +478,7 @@
 
 	size_in = ALIGN(size_in, 8);
 	if (size_in != size) {
-		pr_err("smem_find(%d, %d): wrong size %d\n",
+		SMEM_INFO("smem_find(%u, %u): wrong size %u\n",
 			id, size_in, size);
 		return 0;
 	}
@@ -271,6 +492,189 @@
 }
 EXPORT_SYMBOL(smem_find);
 
+/**
+ * smem_find_to_proc - Find existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size_in:  Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	unsigned size;
+	void *ptr;
+
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc,
+									flags);
+
+	ptr = smem_get_entry_to_proc(id, &size, to_proc, flags);
+	if (!ptr)
+		return 0;
+
+	size_in = ALIGN(size_in, 8);
+	if (size_in != size) {
+		SMEM_INFO("smem_find_to_proc(%u, %u, %u, %u): wrong size %u\n",
+			id, size_in, to_proc, flags, size);
+		return 0;
+	}
+
+	return ptr;
+}
+EXPORT_SYMBOL(smem_find_to_proc);
+
+/**
+ * alloc_item_nonsecure - Allocate an SMEM item in the nonsecure partition
+ *
+ * @id:              ID of SMEM item
+ * @size_in:         Size to allocate
+ * @returns:         Pointer to SMEM item or NULL for error
+ *
+ * Assumes the id parameter is valid and does not already exist.  Assumes
+ * size_in is already adjusted for alignment, if necessary.  Requires the
+ * remote spinlock to already be locked.
+ */
+static void *alloc_item_nonsecure(unsigned id, unsigned size_in)
+{
+	void *smem_base = MSM_SHARED_RAM_BASE;
+	struct smem_shared *shared = smem_base;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	void *ret = NULL;
+
+	if (shared->heap_info.heap_remaining >= size_in) {
+		toc[id].offset = shared->heap_info.free_offset;
+		toc[id].size = size_in;
+		/*
+		 * wmb() is necessary to ensure the allocation data is
+		 * consistent before setting the allocated flag to prevent race
+		 * conditions with remote processors
+		 */
+		wmb();
+		toc[id].allocated = 1;
+
+		shared->heap_info.free_offset += size_in;
+		shared->heap_info.heap_remaining -= size_in;
+		ret = smem_base + toc[id].offset;
+		/*
+		 * wmb() is necessary to ensure the heap data is consistent
+		 * before continuing to prevent race conditions with remote
+		 * processors
+		 */
+		wmb();
+	} else {
+		SMEM_INFO("%s: id %u not enough memory %u (required %u)\n",
+			__func__, id, shared->heap_info.heap_remaining,
+			size_in);
+	}
+
+	return ret;
+}
+
+/**
+ * alloc_item_secure - Allocate an SMEM item in a secure partition
+ *
+ * @id:              ID of SMEM item
+ * @size_in:         Size to allocate
+ * @to_proc:         SMEM host that shares the item with apps
+ * @flags:           Item attribute flags
+ * @returns:         Pointer to SMEM item or NULL for error
+ *
+ * Assumes the id parameter is valid and does  not already exist.  Assumes
+ * size_in is the raw size requested by the client.  Assumes to_proc is a valid
+ * host, and a valid partition to that host exists.  Requires the remote
+ * spinlock to already be locked.
+ */
+static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	void *smem_base = MSM_SHARED_RAM_BASE;
+	struct smem_partition_header *hdr;
+	struct smem_partition_allocation_header *alloc_hdr;
+	uint32_t a_hdr_size;
+	uint32_t a_data_size;
+	uint32_t size_cacheline;
+	uint32_t free_space;
+	uint32_t partition_num;
+	void *ret = NULL;
+
+	hdr = smem_base + partitions[to_proc].offset;
+	partition_num = partitions[to_proc].partition_num;
+
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR(
+			"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								hdr);
+		BUG();
+	}
+
+	size_cacheline = partitions[to_proc].size_cacheline;
+	free_space = hdr->offset_free_cached -
+					hdr->offset_free_uncached;
+
+	if (flags & SMEM_ITEM_CACHED_FLAG) {
+		a_hdr_size = ALIGN(sizeof(*alloc_hdr), size_cacheline);
+		a_data_size = ALIGN(size_in, size_cacheline);
+		if (free_space < a_hdr_size + a_data_size) {
+			SMEM_INFO(
+				"%s: id %u not enough memory %u (required %u)\n",
+						__func__, id, free_space,
+						a_hdr_size + a_data_size);
+			return ret;
+		}
+		alloc_hdr = (void *)(hdr) + hdr->offset_free_cached -
+								a_hdr_size;
+		alloc_hdr->canary = SMEM_ALLOCATION_CANARY;
+		alloc_hdr->smem_type = id;
+		alloc_hdr->size = a_data_size;
+		alloc_hdr->padding_data = a_data_size - size_in;
+		alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr);
+		hdr->offset_free_cached = hdr->offset_free_cached -
+						a_hdr_size - a_data_size;
+		ret = (void *)(alloc_hdr) - a_data_size;
+		/*
+		 * The SMEM protocol currently does not support cacheable
+		 * areas within the smem region, but if it ever does in the
+		 * future, then cache management needs to be done here.
+		 * The area of memory this item is allocated from will need to
+		 * be dynamically made cachable, and a cache flush of the
+		 * allocation header using __cpuc_flush_dcache_area and
+		 * outer_flush_area will need to be done.
+		 */
+	} else {
+		a_hdr_size = sizeof(*alloc_hdr);
+		a_data_size = ALIGN(size_in, 8);
+		if (free_space < a_hdr_size + a_data_size) {
+			SMEM_INFO(
+				"%s: id %u not enough memory %u (required %u)\n",
+						__func__, id, free_space,
+						a_hdr_size + a_data_size);
+			return ret;
+		}
+		alloc_hdr = (void *)(hdr) + hdr->offset_free_uncached;
+		alloc_hdr->canary = SMEM_ALLOCATION_CANARY;
+		alloc_hdr->smem_type = id;
+		alloc_hdr->size = a_data_size;
+		alloc_hdr->padding_data = a_data_size - size_in;
+		alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr);
+		hdr->offset_free_uncached = hdr->offset_free_uncached +
+						a_hdr_size + a_data_size;
+		ret = alloc_hdr + 1;
+	}
+	/*
+	 * wmb() is necessary to ensure the heap and allocation data is
+	 * consistent before continuing to prevent race conditions with remote
+	 * processors
+	 */
+	wmb();
+
+	return ret;
+}
+
 /* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
  * it allocates it and then returns the pointer to it.
  */
@@ -285,13 +689,15 @@
 	if (!smem_initialized_check())
 		return NULL;
 
-	if (id >= SMEM_NUM_ITEMS)
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %u\n", __func__, id);
 		return NULL;
+	}
 
 	if (unlikely(!spinlocks_initialized)) {
 		rc = init_smem_remote_spinlock();
 		if (unlikely(rc)) {
-			pr_err("%s: remote spinlock init failed %d\n",
+			SMEM_INFO("%s: remote spinlock init failed %d\n",
 								__func__, rc);
 			return NULL;
 		}
@@ -300,34 +706,102 @@
 	size_in = ALIGN(size_in, 8);
 	remote_spin_lock_irqsave(&remote_spinlock, flags);
 	if (toc[id].allocated) {
-		SMEM_DBG("%s: %u already allocated\n", __func__, id);
+		SMEM_INFO("%s: %u already allocated\n", __func__, id);
 		if (size_in != toc[id].size)
-			pr_err("%s: wrong size %u (expected %u)\n",
+			SMEM_INFO("%s: wrong size %u (expected %u)\n",
 				__func__, toc[id].size, size_in);
 		else
 			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
 	} else if (id > SMEM_FIXED_ITEM_LAST) {
-		SMEM_DBG("%s: allocating %u\n", __func__, id);
-		if (shared->heap_info.heap_remaining >= size_in) {
-			toc[id].offset = shared->heap_info.free_offset;
-			toc[id].size = size_in;
-			wmb();
-			toc[id].allocated = 1;
-
-			shared->heap_info.free_offset += size_in;
-			shared->heap_info.heap_remaining -= size_in;
-			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
-		} else
-			pr_err("%s: not enough memory %u (required %u)\n",
-				__func__, shared->heap_info.heap_remaining,
-				size_in);
+		SMEM_INFO("%s: allocating %u\n", __func__, id);
+		ret = alloc_item_nonsecure(id, size_in);
 	}
-	wmb();
 	remote_spin_unlock_irqrestore(&remote_spinlock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(smem_alloc2);
 
+/**
+ * smem_alloc2_to_proc - Find an existing item, otherwise allocate it with
+ *				security support
+ *
+ * @id:       ID of SMEM item
+ * @size_in:  Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it couldn't be found/allocated
+ */
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	unsigned long lflags;
+	void *ret = NULL;
+	int rc;
+	unsigned size_out;
+	unsigned a_size_in;
+
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc,
+									flags);
+
+	if (!smem_initialized_check())
+		return NULL;
+
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %u\n", __func__, id);
+		return NULL;
+	}
+
+	if (!(flags & SMEM_ANY_HOST_FLAG) && to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("%s: invalid to_proc %u for id %u\n", __func__,
+								to_proc, id);
+		return NULL;
+	}
+
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			SMEM_INFO("%s: id:%u remote spinlock init failed %d\n",
+							__func__, id, rc);
+			return NULL;
+		}
+	}
+
+	a_size_in = ALIGN(size_in, 8);
+	remote_spin_lock_irqsave(&remote_spinlock, lflags);
+
+	ret = __smem_get_entry_to_proc(id, &size_out, to_proc, flags, true,
+									false);
+	if (ret) {
+		SMEM_INFO("%s: %u already allocated\n", __func__, id);
+		if (a_size_in == size_out) {
+			remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+			return ret;
+		} else {
+			remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+			SMEM_INFO("%s: id %u wrong size %u (expected %u)\n",
+				__func__, id, size_out, a_size_in);
+			return NULL;
+		}
+	}
+
+	if (id > SMEM_FIXED_ITEM_LAST) {
+		SMEM_INFO("%s: allocating %u size %u to_proc %u flags %u\n",
+					__func__, id, size_in, to_proc, flags);
+		if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
+			ret = alloc_item_nonsecure(id, a_size_in);
+		else
+			ret = alloc_item_secure(id, size_in, to_proc, flags);
+
+	} else {
+		SMEM_INFO("%s: attempted to allocate non-dynamic item %u\n",
+								__func__, id);
+	}
+
+	remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+	return ret;
+}
+EXPORT_SYMBOL(smem_alloc2_to_proc);
+
 void *smem_get_entry(unsigned id, unsigned *size)
 {
 	return __smem_get_entry(id, size, false, true);
@@ -335,6 +809,24 @@
 EXPORT_SYMBOL(smem_get_entry);
 
 /**
+ * smem_get_entry_to_proc - Get existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size:     Pointer to size variable for storing the result
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_get_entry_to_proc(unsigned id, unsigned *size, unsigned to_proc,
+								unsigned flags)
+{
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, *size, to_proc, flags);
+
+	return __smem_get_entry_to_proc(id, size, to_proc, flags, false, true);
+}
+EXPORT_SYMBOL(smem_get_entry_to_proc);
+
+/**
  * smem_get_entry_no_rlock - Get existing item without using remote spinlock
  *
  * @id:       ID of SMEM item
@@ -365,9 +857,50 @@
 EXPORT_SYMBOL(smem_get_remote_spinlock);
 
 /**
+ * smem_get_free_space() - Get the available allocation free space for a
+ *				partition
+ *
+ * @to_proc: remote SMEM host.  Determines the applicable partition
+ * @returns: size in bytes available to allocate
+ *
+ * Helper function for SMD so that SMD only scans the channel allocation
+ * table for a partition when it is reasonably certain that a channel has
+ * actually been created, because scanning can be expensive.  Creating a channel
+ * will consume some of the free space in a partition, so SMD can compare the
+ * last free space size against the current free space size to determine if
+ * a channel may have been created.  SMD can't do this directly, because the
+ * necessary partition internals are restricted to just SMEM.
+ */
+unsigned smem_get_free_space(unsigned to_proc)
+{
+	struct smem_partition_header *hdr;
+	struct smem_shared *shared;
+
+	if (to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		pr_err("%s: invalid to_proc:%d\n", __func__, to_proc);
+		return UINT_MAX;
+	}
+
+	if (partitions[to_proc].offset) {
+		if (unlikely(OVERFLOW_ADD_UNSIGNED(uintptr_t,
+					(uintptr_t)smem_areas[0].virt_addr,
+					partitions[to_proc].offset))) {
+			pr_err("%s: unexpected overflow detected\n", __func__);
+			return UINT_MAX;
+		}
+		hdr = smem_areas[0].virt_addr + partitions[to_proc].offset;
+		return hdr->offset_free_cached - hdr->offset_free_uncached;
+	} else {
+		shared = (void *)MSM_SHARED_RAM_BASE;
+		return shared->heap_info.heap_remaining;
+	}
+}
+EXPORT_SYMBOL(smem_get_free_space);
+
+/**
  * init_smem_remote_spinlock - Reentrant remote spinlock initialization
  *
- * @returns: sucess or error code for failure
+ * @returns: success or error code for failure
  */
 static int init_smem_remote_spinlock(void)
 {
@@ -408,7 +941,7 @@
 
 	if (likely(checked)) {
 		if (unlikely(!is_inited))
-			pr_err("%s: smem not initialized\n", __func__);
+			LOG_ERR("%s: smem not initialized\n", __func__);
 		return is_inited;
 	}
 
@@ -416,7 +949,7 @@
 	if (checked) {
 		spin_unlock_irqrestore(&smem_init_check_lock, flags);
 		if (unlikely(!is_inited))
-			pr_err("%s: smem not initialized\n", __func__);
+			LOG_ERR("%s: smem not initialized\n", __func__);
 		return is_inited;
 	}
 
@@ -431,8 +964,17 @@
 									true);
 	if (version_array == NULL)
 		goto failed;
-	if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16)
+
+	/*
+	 * The Modem SBL is now the Master SBL version and is required to
+	 * pre-initialize SMEM and fill in any necessary configuration
+	 * structures.  Without the extra configuration data, the SMEM driver
+	 * cannot be properly initialized.
+	 */
+	if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16) {
+		pr_err("%s: SBL version not correct\n", __func__);
 		goto failed;
+	}
 
 	is_inited = 1;
 	checked = 1;
@@ -443,7 +985,8 @@
 	is_inited = 0;
 	checked = 1;
 	spin_unlock_irqrestore(&smem_init_check_lock, flags);
-	pr_err("%s: bootloader failure detected, shared memory not inited\n",
+	LOG_ERR(
+		"%s: shared memory needs to be initialized by SBL before booting\n",
 								__func__);
 	return is_inited;
 }
@@ -458,7 +1001,7 @@
 
 		notifier = container_of(this,
 					struct restart_notifier_block, nb);
-		SMEM_DBG("%s: ssrestart for processor %d ('%s')\n",
+		SMEM_INFO("%s: ssrestart for processor %d ('%s')\n",
 				__func__, notifier->processor,
 				notifier->name);
 
@@ -478,8 +1021,8 @@
 			ret = do_elf_ramdump(smem_ramdump_dev,
 					smem_ramdump_segments, 1);
 			if (ret < 0)
-				pr_err("%s: unable to dump smem %d\n", __func__,
-						ret);
+				LOG_ERR("%s: unable to dump smem %d\n",
+								__func__, ret);
 		}
 	}
 
@@ -494,7 +1037,7 @@
 
 	smem_ramdump_dev = create_ramdump_device("smem", NULL);
 	if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
-		pr_err("%s: Unable to create smem ramdump device.\n",
+		LOG_ERR("%s: Unable to create smem ramdump device.\n",
 			__func__);
 		smem_ramdump_dev = NULL;
 	}
@@ -546,6 +1089,124 @@
 	mutex_unlock(&smem_module_init_notifier_lock);
 }
 
+/**
+ * smem_init_security_partition - Init local structures for a secured smem
+ *                   partition that has apps as one of the hosts
+ *
+ * @entry:           Entry in the security TOC for the partition to init
+ * @num:             Partition ID
+ *
+ * Initialize local data structures to point to a secured smem partition
+ * that is accessible by apps and another processor.  Assumes that one of the
+ * listed hosts is apps.  Verifiess that the partition is valid, otherwise will
+ * skip.  Checks for memory corruption and will BUG() if detected.  Assumes
+ * smem_areas is already initialized and that smem_areas[0] corresponds to the
+ * smem region with the secured partitions.
+ */
+static void smem_init_security_partition(struct smem_toc_entry *entry,
+								uint32_t num)
+{
+	uint16_t remote_host;
+	struct smem_partition_header *hdr;
+
+	if (!entry->offset) {
+		SMEM_INFO("Skipping smem partition %d - bad offset\n", num);
+		return;
+	}
+	if (!entry->size) {
+		SMEM_INFO("Skipping smem partition %d - bad size\n", num);
+		return;
+	}
+	if (!entry->size_cacheline) {
+		SMEM_INFO("Skipping smem partition %d - bad cacheline\n", num);
+		return;
+	}
+
+	if (entry->host0 == SMEM_APPS)
+		remote_host = entry->host1;
+	else
+		remote_host = entry->host0;
+
+	if (remote_host >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("Skipping smem partition %d - bad remote:%d\n", num,
+								remote_host);
+		return;
+	}
+	if (partitions[remote_host].offset) {
+		SMEM_INFO("Skipping smem partition %d - duplicate of %d\n", num,
+					partitions[remote_host].partition_num);
+		return;
+	}
+
+	hdr = smem_areas[0].virt_addr + entry->offset;
+
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR("Smem partition %d hdr magic is bad\n", num);
+		BUG();
+	}
+	if (!hdr->size) {
+		LOG_ERR("Smem partition %d size is 0\n", num);
+		BUG();
+	}
+	if (hdr->offset_free_uncached > hdr->size) {
+		LOG_ERR("Smem partition %d uncached heap exceeds size\n", num);
+		BUG();
+	}
+	if (hdr->offset_free_cached > hdr->size) {
+		LOG_ERR("Smem partition %d cached heap exceeds size\n", num);
+		BUG();
+	}
+	if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) {
+		LOG_ERR("Smem partition %d hosts don't match TOC\n", num);
+		BUG();
+	}
+	if (hdr->host0 != remote_host && hdr->host1 != remote_host) {
+		LOG_ERR("Smem partition %d hosts don't match TOC\n", num);
+		BUG();
+	}
+
+	partitions[remote_host].partition_num = num;
+	partitions[remote_host].offset = entry->offset;
+	partitions[remote_host].size_cacheline = entry->size_cacheline;
+	SMEM_INFO("Partition %d offset:%x remote:%d\n", num, entry->offset,
+								remote_host);
+}
+
+/**
+ * smem_init_security - Init local support for secured smem
+ *
+ * Looks for a valid security TOC, and if one is found, parses it looking for
+ * partitions that apps can access.  If any such partitions are found, do the
+ * required local initialization to support them.  Assumes smem_areas is inited
+ * and smem_area[0] corresponds to the smem region with the TOC.
+ */
+static void smem_init_security(void)
+{
+	struct smem_toc *toc;
+	uint32_t i;
+
+	SMEM_DBG("%s\n", __func__);
+
+	toc = smem_areas[0].virt_addr + smem_areas[0].size - 4 * 1024;
+
+	if (toc->identifier != SMEM_TOC_IDENTIFIER) {
+		LOG_ERR("%s failed: invalid TOC magic\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < toc->num_entries; ++i) {
+		SMEM_DBG("Partition %d host0:%d host1:%d\n", i,
+							toc->entry[i].host0,
+							toc->entry[i].host1);
+
+		if (toc->entry[i].host0 == SMEM_APPS ||
+					toc->entry[i].host1 == SMEM_APPS)
+			smem_init_security_partition(&toc->entry[i], i);
+	}
+
+	SMEM_DBG("%s done\n", __func__);
+}
+
 static int msm_smem_probe(struct platform_device *pdev)
 {
 	char *key;
@@ -558,6 +1219,7 @@
 	struct ramdump_segment *ramdump_segments_tmp = NULL;
 	struct smem_area *smem_areas_tmp = NULL;
 	int smem_idx = 0;
+	bool security_enabled;
 
 	if (!smem_initialized_check())
 		return -ENODEV;
@@ -565,7 +1227,7 @@
 	key = "irq-reg-base";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
-		pr_err("%s: missing '%s'\n", __func__, key);
+		LOG_ERR("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
 
@@ -580,7 +1242,7 @@
 
 		++num_smem_areas;
 		if (num_smem_areas > 999) {
-			pr_err("%s: max num aux mem regions reached\n",
+			LOG_ERR("%s: max num aux mem regions reached\n",
 								__func__);
 			break;
 		}
@@ -589,14 +1251,14 @@
 	key = "smem";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
-		pr_err("%s: missing '%s'\n", __func__, key);
+		LOG_ERR("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
 
 	smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
 				GFP_KERNEL);
 	if (!smem_areas_tmp) {
-		pr_err("%s: smem areas kmalloc failed\n", __func__);
+		LOG_ERR("%s: smem areas kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
@@ -604,7 +1266,7 @@
 	ramdump_segments_tmp = kmalloc_array(num_smem_areas,
 			sizeof(struct ramdump_segment), GFP_KERNEL);
 	if (!ramdump_segments_tmp) {
-		pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+		LOG_ERR("%s: ramdump segment kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
@@ -640,7 +1302,7 @@
 				smem_areas_tmp[smem_idx].virt_addr);
 
 		if (!smem_areas_tmp[smem_idx].virt_addr) {
-			pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
+			LOG_ERR("%s: ioremap_nocache() of addr:%pa size: %pa\n",
 				__func__,
 				&smem_areas_tmp[smem_idx].phys_addr,
 				&smem_areas_tmp[smem_idx].size);
@@ -651,7 +1313,8 @@
 		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
 				smem_areas_tmp[smem_idx].size)) {
-			pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+			LOG_ERR(
+				"%s: invalid virtual address block %i: %p:%pa\n",
 					__func__, smem_idx,
 					smem_areas_tmp[smem_idx].virt_addr,
 					&smem_areas_tmp[smem_idx].size);
@@ -662,18 +1325,26 @@
 
 		++smem_idx;
 		if (smem_idx > 999) {
-			pr_err("%s: max num aux mem regions reached\n",
+			LOG_ERR("%s: max num aux mem regions reached\n",
 							__func__);
 			break;
 		}
 	}
 
-	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
-	if (ret)
-		pr_err("%s: of_platform_populate failed %d\n", __func__, ret);
-
 	smem_areas = smem_areas_tmp;
 	smem_ramdump_segments = ramdump_segments_tmp;
+
+	key = "mpu-enabled";
+	security_enabled = of_property_read_bool(pdev->dev.of_node, key);
+	if (security_enabled) {
+		SMEM_INFO("smem security enabled\n");
+		smem_init_security();
+	}
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (ret)
+		LOG_ERR("%s: of_platform_populate failed %d\n", __func__, ret);
+
 	return 0;
 
 free_smem_areas:
@@ -710,15 +1381,21 @@
 
 	registered = true;
 
+	smem_ipc_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smem");
+	if (!smem_ipc_log_ctx) {
+		pr_err("%s: unable to create logging context\n", __func__);
+		msm_smem_debug_mask = 0;
+	}
+
 	rc = init_smem_remote_spinlock();
 	if (rc) {
-		pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+		LOG_ERR("%s: remote spinlock init failed %d\n", __func__, rc);
 		return rc;
 	}
 
 	rc = platform_driver_register(&msm_smem_driver);
 	if (rc) {
-		pr_err("%s: msm_smem_driver register failed %d\n",
+		LOG_ERR("%s: msm_smem_driver register failed %d\n",
 							__func__, rc);
 		return rc;
 	}
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index ceb8028..3fa842f 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -76,4 +76,21 @@
  * @nb: Notifier block to be unregistered
  */
 int smem_module_init_notifier_unregister(struct notifier_block *nb);
+
+/**
+ * smem_get_free_space() - Get the available allocation free space for a
+ *				partition
+ *
+ * @to_proc: remote SMEM host.  Determines the applicable partition
+ * @returns: size in bytes available to allocate
+ *
+ * Helper function for SMD so that SMD only scans the channel allocation
+ * table for a partition when it is reasonably certain that a channel has
+ * actually been created, because scanning can be expensive.  Creating a channel
+ * will consume some of the free space in a partition, so SMD can compare the
+ * last free space size against the current free space size to determine if
+ * a channel may have been created.  SMD can't do this directly, because the
+ * necessary partition internals are restricted to just SMEM.
+ */
+unsigned smem_get_free_space(unsigned to_proc);
 #endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 888cd5e..53bbe20 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -1035,56 +1035,64 @@
 
 	msm_soc_device = soc_device_to_device(soc_dev);
 	populate_soc_sysfs_files(msm_soc_device);
+
 	err = sysdev_class_register(&soc_sysdev_class);
 	if (err) {
 		pr_err("%s: sysdev_class_register fail (%d)\n",
 		       __func__, err);
-		return err;
+		goto socinfo_init_err;
 	}
+
 	err = sysdev_register(&soc_sys_device);
 	if (err) {
 		pr_err("%s: sysdev_register fail (%d)\n",
 		       __func__, err);
-		return err;
+		goto socinfo_init_err;
 	}
+
 	socinfo_create_files(&soc_sys_device, socinfo_v1_files,
 				ARRAY_SIZE(socinfo_v1_files));
 	if (socinfo->v1.format < 2)
-		return err;
+		goto socinfo_init_err;
+
 	socinfo_create_files(&soc_sys_device, socinfo_v2_files,
 				ARRAY_SIZE(socinfo_v2_files));
 
 	if (socinfo->v1.format < 3)
-		return err;
+		goto socinfo_init_err;
 
 	socinfo_create_files(&soc_sys_device, socinfo_v3_files,
 				ARRAY_SIZE(socinfo_v3_files));
 
 	if (socinfo->v1.format < 4)
-		return err;
+		goto socinfo_init_err;
 
 	socinfo_create_files(&soc_sys_device, socinfo_v4_files,
 				ARRAY_SIZE(socinfo_v4_files));
 
 	if (socinfo->v1.format < 5)
-		return err;
+		goto socinfo_init_err;
 
 	socinfo_create_files(&soc_sys_device, socinfo_v5_files,
 				ARRAY_SIZE(socinfo_v5_files));
 
 	if (socinfo->v1.format < 6)
-		return err;
+		goto socinfo_init_err;
 
 	socinfo_create_files(&soc_sys_device, socinfo_v6_files,
 				ARRAY_SIZE(socinfo_v6_files));
 
 	if (socinfo->v1.format < 7)
-		return err;
+		goto socinfo_init_err;
 
 	socinfo_create_files(&soc_sys_device, socinfo_v7_files,
 				ARRAY_SIZE(socinfo_v7_files));
 
 	return 0;
+
+socinfo_init_err:
+	 kfree(soc_dev_attr);
+         return err;
 }
 
 arch_initcall(socinfo_init_sysdev);
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 3207011..1769402 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -24,6 +24,7 @@
 	MSM_SPM_L2_MODE_DISABLED = MSM_SPM_MODE_DISABLED,
 	MSM_SPM_L2_MODE_RETENTION,
 	MSM_SPM_L2_MODE_GDHS,
+	MSM_SPM_L2_MODE_PC_NO_RPM,
 	MSM_SPM_L2_MODE_POWER_COLLAPSE,
 };
 
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 3ac1348..19b0b80 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -397,6 +397,7 @@
 	struct mode_of of_l2_modes[] = {
 		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
 		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
+		{"qcom,saw2-spm-cmd-pc-no-rpm", MSM_SPM_L2_MODE_PC_NO_RPM, 1},
 		{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
 	};
 
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index cf0e669..3e4fa84 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -163,6 +163,6 @@
 		}
 	}
 
-	init_FIQ();
+	init_FIQ(FIQ_START);
 }
 
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 194c5f6..7b9f754 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -436,24 +436,28 @@
 	select TLS_REG_EMUL if SMP || !MMU
 	select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 	select CPU_USE_DOMAINS if MMU
+	select NEED_KUSER_HELPERS
 
 config CPU_32v4
 	bool
 	select TLS_REG_EMUL if SMP || !MMU
 	select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 	select CPU_USE_DOMAINS if MMU
+	select NEED_KUSER_HELPERS
 
 config CPU_32v4T
 	bool
 	select TLS_REG_EMUL if SMP || !MMU
 	select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 	select CPU_USE_DOMAINS if MMU
+	select NEED_KUSER_HELPERS
 
 config CPU_32v5
 	bool
 	select TLS_REG_EMUL if SMP || !MMU
 	select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 	select CPU_USE_DOMAINS if MMU
+	select NEED_KUSER_HELPERS
 
 config CPU_32v6
 	bool
@@ -792,6 +796,7 @@
 
 config TLS_REG_EMUL
 	bool
+	select NEED_KUSER_HELPERS
 	help
 	  An SMP system using a pre-ARMv6 processor (there are apparently
 	  a few prototypes like that in existence) and therefore access to
@@ -799,11 +804,43 @@
 
 config NEEDS_SYSCALL_FOR_CMPXCHG
 	bool
+	select NEED_KUSER_HELPERS
 	help
 	  SMP on a pre-ARMv6 processor?  Well OK then.
 	  Forget about fast user space cmpxchg support.
 	  It is just not possible.
 
+config NEED_KUSER_HELPERS
+	bool
+
+config KUSER_HELPERS
+	bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS
+	default y
+	help
+	  Warning: disabling this option may break user programs.
+
+	  Provide kuser helpers in the vector page.  The kernel provides
+	  helper code to userspace in read only form at a fixed location
+	  in the high vector page to allow userspace to be independent of
+	  the CPU type fitted to the system.  This permits binaries to be
+	  run on ARMv4 through to ARMv7 without modification.
+
+	  See Documentation/arm/kernel_user_helpers.txt for details.
+
+	  However, the fixed address nature of these helpers can be used
+	  by ROP (return orientated programming) authors when creating
+	  exploits.
+
+	  If all of the binaries and libraries which run on your platform
+	  are built specifically for your platform, and make no use of
+	  these helpers, then you can turn this option off to hinder
+	  such exploits. However, in that case, if a binary or library
+	  relying on those helpers is run, it will receive a SIGILL signal,
+	  which will terminate the program.
+
+	  Say N here only if you are absolutely certain that you do not
+	  need these helpers; otherwise, the safe option is to say Y.
+
 config DMA_CACHE_RWFO
 	bool "Enable read/write for ownership DMA cache maintenance"
 	depends on CPU_V6K && SMP
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e82ea2b..34ae4e6 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -734,6 +734,46 @@
 #endif
 }
 
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+void print_vmalloc_lowmem_info(void)
+{
+	int i;
+	void *va_start, *va_end;
+
+	printk(KERN_NOTICE
+		"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		MLM(VMALLOC_START, VMALLOC_END));
+
+	for (i = meminfo.nr_banks - 1; i >= 0; i--) {
+		if (!meminfo.bank[i].highmem) {
+			va_start = __va(meminfo.bank[i].start);
+			va_end = __va(meminfo.bank[i].start +
+						meminfo.bank[i].size);
+			printk(KERN_NOTICE
+			 "	    lowmem : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+			MLM((unsigned long)va_start, (unsigned long)va_end));
+		}
+		if (i && ((meminfo.bank[i-1].start + meminfo.bank[i-1].size) !=
+			   meminfo.bank[i].start)) {
+			if (meminfo.bank[i-1].start + meminfo.bank[i-1].size
+				   <= MAX_HOLE_ADDRESS) {
+				va_start = __va(meminfo.bank[i-1].start
+						+ meminfo.bank[i-1].size);
+				va_end = __va(meminfo.bank[i].start);
+				printk(KERN_NOTICE
+				"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+					   MLM((unsigned long)va_start,
+						   (unsigned long)va_end));
+			}
+		}
+	}
+}
+#endif
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -814,10 +854,6 @@
 		reserved_pages << (PAGE_SHIFT-10),
 		totalhigh_pages << (PAGE_SHIFT-10));
 
-#define MLK(b, t) b, t, ((t) - (b)) >> 10
-#define MLM(b, t) b, t, ((t) - (b)) >> 20
-#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
-
 	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -827,20 +863,7 @@
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #endif
-			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
-			"    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-			"    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#ifdef CONFIG_HIGHMEM
-			"    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-#ifdef CONFIG_MODULES
-			"    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-			"      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
-
+			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n",
 			MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
 				(PAGE_SIZE)),
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -852,25 +875,39 @@
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 #endif
-			MLK(FIXADDR_START, FIXADDR_TOP),
-			MLM(VMALLOC_START, VMALLOC_END),
-			MLM(PAGE_OFFSET, (unsigned long)high_memory),
+			MLK(FIXADDR_START, FIXADDR_TOP));
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	print_vmalloc_lowmem_info();
+#else
+	printk(KERN_NOTICE
+		   "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+		   "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		   MLM(VMALLOC_START, VMALLOC_END),
+		   MLM(PAGE_OFFSET, (unsigned long)high_memory));
+#endif
 #ifdef CONFIG_HIGHMEM
-			MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
+	printk(KERN_NOTICE
+		   "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+#ifdef CONFIG_MODULES
+		   "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+		   "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
+#ifdef CONFIG_HIGHMEM
+		   MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
 				(PAGE_SIZE)),
 #endif
 #ifdef CONFIG_MODULES
-			MLM(MODULES_VADDR, MODULES_END),
+		   MLM(MODULES_VADDR, MODULES_END),
 #endif
 
-			MLK_ROUNDUP(_text, _etext),
-			MLK_ROUNDUP(__init_begin, __init_end),
-			MLK_ROUNDUP(_sdata, _edata),
-			MLK_ROUNDUP(__bss_start, __bss_stop));
-
-#undef MLK
-#undef MLM
-#undef MLK_ROUNDUP
+		   MLK_ROUNDUP(_text, _etext),
+		   MLK_ROUNDUP(__init_begin, __init_end),
+		   MLK_ROUNDUP(_sdata, _edata),
+		   MLK_ROUNDUP(__bss_start, __bss_stop));
 
 	/*
 	 * Check boundaries twice: Some fundamental inconsistencies can
@@ -878,7 +915,7 @@
 	 */
 #ifdef CONFIG_MMU
 	BUILD_BUG_ON(TASK_SIZE				> MODULES_VADDR);
-	BUG_ON(TASK_SIZE 				> MODULES_VADDR);
+	BUG_ON(TASK_SIZE				> MODULES_VADDR);
 #endif
 
 #ifdef CONFIG_HIGHMEM
@@ -897,6 +934,9 @@
 	}
 }
 
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
 void free_initmem(void)
 {
 	unsigned long reclaimed_initmem;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e5a60a9..a1a2e51 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -871,6 +871,7 @@
 {
 	struct map_desc *md;
 	struct vm_struct *vm;
+	int rc = 0;
 
 	if (!nr)
 		return;
@@ -881,11 +882,13 @@
 		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-		vm->phys_addr = __pfn_to_phys(md->pfn); 
-		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+		vm->phys_addr = __pfn_to_phys(md->pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(md->type);
 		vm->caller = iotable_init;
-		vm_area_add_early(vm++);
+		rc = vm_area_check_early(vm);
+		if (!rc)
+			vm_area_add_early(vm++);
 	}
 }
 
@@ -999,6 +1002,18 @@
 {
 	int i, j, highmem = 0;
 
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	unsigned long hole_start;
+	for (i = 0; i < (meminfo.nr_banks - 1); i++) {
+		hole_start = meminfo.bank[i].start + meminfo.bank[i].size;
+		if (hole_start != meminfo.bank[i+1].start) {
+			if (hole_start <= MAX_HOLE_ADDRESS) {
+				vmalloc_min = (void *) (vmalloc_min +
+				(meminfo.bank[i+1].start - hole_start));
+			}
+		}
+	}
+#endif
 #ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
 	find_memory_hole();
 #endif
@@ -1188,7 +1203,7 @@
 	/*
 	 * Allocate the vector page early.
 	 */
-	vectors = early_alloc(PAGE_SIZE);
+	vectors = early_alloc(PAGE_SIZE * 2);
 
 	early_trap_init(vectors);
 
@@ -1233,15 +1248,27 @@
 	map.pfn = __phys_to_pfn(virt_to_phys(vectors));
 	map.virtual = 0xffff0000;
 	map.length = PAGE_SIZE;
+#ifdef CONFIG_KUSER_HELPERS
 	map.type = MT_HIGH_VECTORS;
+#else
+	map.type = MT_LOW_VECTORS;
+#endif
 	create_mapping(&map);
 
 	if (!vectors_high()) {
 		map.virtual = 0;
+		map.length = PAGE_SIZE * 2;
 		map.type = MT_LOW_VECTORS;
 		create_mapping(&map);
 	}
 
+	/* Now create a kernel read-only mapping */
+	map.pfn += 1;
+	map.virtual = 0xffff0000 + PAGE_SIZE;
+	map.length = PAGE_SIZE;
+	map.type = MT_LOW_VECTORS;
+	create_mapping(&map);
+
 	/*
 	 * Ask the machine support to map in the statically mapped devices.
 	 */
@@ -1382,12 +1409,21 @@
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
+	struct vm_struct *vm;
+	phys_addr_t start;
+	phys_addr_t end;
+	unsigned long vaddr;
+	unsigned long pfn;
+	unsigned long length;
+	unsigned int type;
+	int nr = 0;
 
 	/* Map all the lowmem memory banks. */
 	for_each_memblock(memory, reg) {
-		phys_addr_t start = reg->base;
-		phys_addr_t end = start + reg->size;
 		struct map_desc map;
+		nr++;
+		start = reg->base;
+		end = start + reg->size;
 
 		if (end > arm_lowmem_limit)
 			end = arm_lowmem_limit;
@@ -1440,6 +1476,32 @@
 
 		create_mapping(&map);
 	}
+
+	vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
+
+	for_each_memblock(memory, reg) {
+
+		start = reg->base;
+		end = start + reg->size;
+
+		if (end > arm_lowmem_limit)
+			end = arm_lowmem_limit;
+		if (start >= end)
+			break;
+
+		pfn = __phys_to_pfn(start);
+		vaddr = __phys_to_virt(start);
+		length = end - start;
+		type = MT_MEMORY;
+
+		vm->addr = (void *)(vaddr & PAGE_MASK);
+		vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK));
+		vm->phys_addr = __pfn_to_phys(pfn);
+		vm->flags = VM_LOWMEM | VM_ARM_STATIC_MAPPING;
+		vm->flags |= VM_ARM_MTYPE(type);
+		vm->caller = map_lowmem;
+		vm_area_add_early(vm++);
+	}
 }
 
 /*
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c
index 689f81f..9091f03 100644
--- a/arch/arm/plat-mxc/avic.c
+++ b/arch/arm/plat-mxc/avic.c
@@ -199,7 +199,7 @@
 
 #ifdef CONFIG_FIQ
 	/* Initialize FIQ */
-	init_FIQ();
+	init_FIQ(FIQ_START);
 #endif
 
 	printk(KERN_INFO "MXC IRQ initialized\n");
diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c
index 98308ec..5cebccf 100644
--- a/arch/arm/plat-mxc/tzic.c
+++ b/arch/arm/plat-mxc/tzic.c
@@ -180,7 +180,7 @@
 
 #ifdef CONFIG_FIQ
 	/* Initialize FIQ */
-	init_FIQ();
+	init_FIQ(FIQ_START);
 #endif
 
 	pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index bc42c04..fe57bbb 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -533,7 +533,7 @@
 	int i;
 
 #ifdef CONFIG_FIQ
-	init_FIQ();
+	init_FIQ(FIQ_START);
 #endif
 
 	irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
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/base/sync.c b/drivers/base/sync.c
index abde6d9..645a698 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -92,14 +92,14 @@
 void sync_timeline_destroy(struct sync_timeline *obj)
 {
 	obj->destroyed = true;
+	smp_wmb();
 
 	/*
-	 * If this is not the last reference, signal any children
-	 * that their parent is going away.
+	 * signal any children that their parent is going away.
 	 */
+	sync_timeline_signal(obj);
 
-	if (!kref_put(&obj->kref, sync_timeline_free))
-		sync_timeline_signal(obj);
+	kref_put(&obj->kref, sync_timeline_free);
 }
 EXPORT_SYMBOL(sync_timeline_destroy);
 
diff --git a/drivers/bif/bif-core.c b/drivers/bif/bif-core.c
index 7bc9af2..4ff7355 100644
--- a/drivers/bif/bif-core.c
+++ b/drivers/bif/bif-core.c
@@ -205,13 +205,14 @@
 	}
 
 	if (sdev->nvm_function) {
-		pr_debug("  NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d\n",
+		pr_debug("  NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d, nvm_lock_offset=%d\n",
 			sdev->nvm_function->nvm_pointer,
 			sdev->nvm_function->slave_control_channel,
 			(sdev->nvm_function->write_buffer_size
 				? sdev->nvm_function->write_buffer_size : 0),
 			sdev->nvm_function->nvm_base_address,
-			sdev->nvm_function->nvm_size);
+			sdev->nvm_function->nvm_size,
+			sdev->nvm_function->nvm_lock_offset);
 		if (sdev->nvm_function->object_count)
 			pr_debug("  NVM objects:\n");
 		i = 0;
@@ -448,8 +449,13 @@
 		rc = bdev->desc->ops->read_slave_registers(bdev, addr, buf,
 							   len);
 		if (rc)
-			pr_err("read_slave_registers failed, rc=%d\n", rc);
-		return rc;
+			pr_debug("read_slave_registers failed, rc=%d\n", rc);
+		else
+			return rc;
+		/*
+		 * Fall back on individual transactions if high level register
+		 * read failed.
+		 */
 	}
 
 	for (i = 0; i < len; i++) {
@@ -521,8 +527,13 @@
 		rc = bdev->desc->ops->write_slave_registers(bdev, addr, buf,
 							    len);
 		if (rc)
-			pr_err("write_slave_registers failed, rc=%d\n", rc);
-		return rc;
+			pr_debug("write_slave_registers failed, rc=%d\n", rc);
+		else
+			return rc;
+		/*
+		 * Fall back on individual transactions if high level register
+		 * write failed.
+		 */
 	}
 
 	rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA, addr >> 8);
@@ -567,6 +578,233 @@
 	return rc;
 }
 
+/* Perform a read-modify-write sequence on a single BIF slave register. */
+static int _bif_slave_masked_write(struct bif_slave_dev *sdev, u16 addr, u8 val,
+			u8 mask)
+{
+	int rc;
+	u8 reg;
+
+	rc = _bif_slave_read(sdev, addr, &reg, 1);
+	if (rc)
+		return rc;
+
+	reg = (reg & ~mask) | (val & mask);
+
+	return _bif_slave_write(sdev, addr, &reg, 1);
+}
+
+static int _bif_check_task(struct bif_slave_dev *sdev, unsigned int task)
+{
+	if (IS_ERR_OR_NULL(sdev)) {
+		pr_err("Invalid slave device handle=%ld\n", PTR_ERR(sdev));
+		return -EINVAL;
+	} else if (!sdev->bdev) {
+		pr_err("BIF controller has been removed\n");
+		return -ENXIO;
+	} else if (!sdev->slave_ctrl_function
+			|| sdev->slave_ctrl_function->task_count == 0) {
+		pr_err("BIF slave does not support slave control\n");
+		return -ENODEV;
+	} else if (task >= sdev->slave_ctrl_function->task_count) {
+		pr_err("Requested task: %u greater than max: %u for this slave\n",
+			task, sdev->slave_ctrl_function->task_count);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int _bif_task_is_busy(struct bif_slave_dev *sdev, unsigned int task)
+{
+	int rc;
+	u16 addr;
+	u8 reg = 0;
+
+	rc = _bif_check_task(sdev, task);
+	if (rc) {
+		pr_err("Invalid slave device or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Check the task busy state. */
+	addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
+		sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	rc = _bif_slave_read(sdev, addr, &reg, 1);
+	if (rc) {
+		pr_err("BIF slave register read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
+}
+
+static int _bif_enable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
+{
+	int rc;
+	u16 addr;
+	u8 mask;
+
+	rc = _bif_check_task(sdev, task);
+	if (rc) {
+		pr_err("Invalid slave device or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Enable the auto task within the slave */
+	mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+	addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
+		sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
+		/* Set global auto task enable. */
+		mask |= BIT(0);
+	}
+	rc = _bif_slave_masked_write(sdev, addr, 0xFF, mask);
+	if (rc) {
+		pr_err("BIF slave register masked write failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Set global auto task enable if task not in set 0. */
+	if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
+		addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
+		       sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
+		rc = _bif_slave_masked_write(sdev, addr, 0xFF, BIT(0));
+		if (rc) {
+			pr_err("BIF slave register masked write failed, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int _bif_disable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
+{
+	int rc;
+	u16 addr;
+	u8 mask;
+
+	rc = _bif_check_task(sdev, task);
+	if (rc) {
+		pr_err("Invalid slave or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Disable the auto task within the slave */
+	mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+	addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
+		sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	rc = _bif_slave_masked_write(sdev, addr, 0x00, mask);
+	if (rc) {
+		pr_err("BIF slave register masked write failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/*
+ * The MIPI-BIF spec does not define a maximum time in which an NVM write must
+ * complete.  The following delay and recheck count therefore represent
+ * arbitrary but reasonable values.
+ */
+#define NVM_WRITE_POLL_DELAY_MS		20
+#define NVM_WRITE_MAX_POLL_COUNT	50
+
+static int _bif_slave_nvm_raw_write(struct bif_slave_dev *sdev, u16 offset,
+				u8 *buf, int len)
+{
+	int rc = 0;
+	int write_len, poll_count, rc2;
+	u8 write_buf[3];
+
+	if (!sdev->nvm_function) {
+		pr_err("BIF slave has no NVM function\n");
+		return -ENODEV;
+	} else if (offset + len > sdev->nvm_function->nvm_size) {
+		pr_err("write offset + len = %d > NVM size = %d\n",
+			offset + len, sdev->nvm_function->nvm_size);
+		return -EINVAL;
+	} else if (offset < sdev->nvm_function->nvm_lock_offset) {
+		pr_err("write offset = %d < first writable offset = %d\n",
+			offset, sdev->nvm_function->nvm_lock_offset);
+		return -EINVAL;
+	}
+
+	rc = _bif_enable_auto_task(sdev,
+			sdev->nvm_function->slave_control_channel);
+	if (rc) {
+		pr_err("Failed to enable NVM auto task, rc=%d\n", rc);
+		return rc;
+	}
+
+	while (len > 0) {
+		write_len = sdev->nvm_function->write_buffer_size;
+		if (write_len == 0)
+			write_len = 256;
+		write_len = min(write_len, len);
+
+		write_buf[0] = offset >> 8;
+		write_buf[1] = offset;
+		write_buf[2] = (write_len == 256) ? 0 : write_len;
+
+		/* Write offset and size registers. */
+		rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 6,
+					write_buf, 3);
+		if (rc) {
+			pr_err("BIF slave write failed, rc=%d\n", rc);
+			goto done;
+		}
+
+		/* Write to NVM write buffer registers. */
+		rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 9,
+					buf, write_len);
+		if (rc) {
+			pr_err("BIF slave write failed, rc=%d\n", rc);
+			goto done;
+		}
+
+		/*
+		 * Wait for completion of the NVM write which was auto-triggered
+		 * by the register write of the last byte in the NVM write
+		 * buffer.
+		 */
+		poll_count = NVM_WRITE_MAX_POLL_COUNT;
+		do {
+			msleep(NVM_WRITE_POLL_DELAY_MS);
+			rc = _bif_task_is_busy(sdev,
+				sdev->nvm_function->slave_control_channel);
+			poll_count--;
+		} while (rc > 0 && poll_count > 0);
+
+		if (rc < 0) {
+			pr_err("Failed to check task state, rc=%d", rc);
+			goto done;
+		} else if (rc > 0) {
+			pr_err("BIF slave NVM write not completed after %d ms\n",
+			    NVM_WRITE_POLL_DELAY_MS * NVM_WRITE_MAX_POLL_COUNT);
+			rc = -ETIMEDOUT;
+			goto done;
+		}
+
+		len -= write_len;
+		offset += write_len;
+		buf += write_len;
+	}
+
+done:
+	rc2 = _bif_disable_auto_task(sdev,
+			sdev->nvm_function->slave_control_channel);
+	if (rc2) {
+		pr_err("Failed to disable NVM auto task, rc=%d\n", rc2);
+		return rc2;
+	}
+
+	return rc;
+}
+
 /* Takes a mutex if this consumer is not an exclusive bus user. */
 static void bif_ctrl_lock(struct bif_ctrl *ctrl)
 {
@@ -595,25 +833,53 @@
 	bif_ctrl_unlock(&slave->ctrl);
 }
 
+/**
+ * bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
+ * @buffer:	Data to calculate the CRC of
+ * @len:	Length of the data buffer in bytes
+ *
+ * MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects.  This
+ * function performs the CRC calculation while taking into account the bit
+ * ordering used by BIF.
+ */
+u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
+{
+	u16 crc = 0xFFFF;
+
+	while (len--) {
+		crc = crc_ccitt_byte(crc, bitrev8(*buffer));
+		buffer++;
+	}
+	return bitrev16(crc);
+}
+EXPORT_SYMBOL(bif_crc_ccitt);
+
+static u16 bif_object_crc_ccitt(const struct bif_object *object)
+{
+	u16 crc = 0xFFFF;
+	int i;
+
+	crc = crc_ccitt_byte(crc, bitrev8(object->type));
+	crc = crc_ccitt_byte(crc, bitrev8(object->version));
+	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
+	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
+	crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
+	crc = crc_ccitt_byte(crc, bitrev8(object->length));
+
+	for (i = 0; i < object->length - 8; i++)
+		crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));
+
+	return bitrev16(crc);
+}
+
 static int bif_check_task(struct bif_slave *slave, unsigned int task)
 {
 	if (IS_ERR_OR_NULL(slave)) {
-		pr_err("Invalid slave handle.\n");
-		return -EINVAL;
-	} else if (!slave->sdev->bdev) {
-		pr_err("BIF controller has been removed.\n");
-		return -ENXIO;
-	} else if (!slave->sdev->slave_ctrl_function
-			|| slave->sdev->slave_ctrl_function->task_count == 0) {
-		pr_err("BIF slave does not support slave control.\n");
-		return -ENODEV;
-	} else if (task >= slave->sdev->slave_ctrl_function->task_count) {
-		pr_err("Requested task: %u greater than max: %u for this slave\n",
-			task, slave->sdev->slave_ctrl_function->task_count);
+		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
 		return -EINVAL;
 	}
 
-	return 0;
+	return _bif_check_task(slave->sdev, task);
 }
 
 /**
@@ -817,6 +1083,61 @@
 EXPORT_SYMBOL(bif_trigger_task);
 
 /**
+ * bif_enable_auto_task() - enable task auto triggering for the specified task
+ * @slave:	BIF slave handle
+ * @task:	BIF task inside of the slave to configure for automatic
+ *		triggering.  This corresponds to the slave control channel
+ *		specified for a given BIF function inside of the slave.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_enable_auto_task(struct bif_slave *slave, unsigned int task)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+	rc = _bif_enable_auto_task(slave->sdev, task);
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_enable_auto_task);
+
+/**
+ * bif_disable_auto_task() - disable task auto triggering for the specified task
+ * @slave:	BIF slave handle
+ * @task:	BIF task inside of the slave to stop automatic triggering on.
+ *		This corresponds to the slave control channel specified for a
+ *		given BIF function inside of the slave.
+ *
+ * This function should be called after bif_enable_auto_task() in a paired
+ * fashion.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_disable_auto_task(struct bif_slave *slave, unsigned int task)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+	rc = _bif_disable_auto_task(slave->sdev, task);
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_disable_auto_task);
+
+/**
  * bif_task_is_busy() - checks the state of a BIF slave task
  * @slave:	BIF slave handle
  * @task:	BIF task inside of the slave to trigger.  This corresponds to
@@ -828,28 +1149,14 @@
 int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
 {
 	int rc;
-	u16 addr;
-	u8 reg;
 
-	rc = bif_check_task(slave, task);
-	if (rc) {
-		pr_err("Invalid slave or task, rc=%d\n", rc);
-		return rc;
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+		return -EINVAL;
 	}
 
 	bif_slave_ctrl_lock(slave);
-
-	/* Check the task busy state. */
-	addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
-		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
-	rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
-	if (rc) {
-		pr_err("BIF slave register read failed, rc=%d\n", rc);
-		goto done;
-	}
-
-	rc = (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
-done:
+	rc = _bif_task_is_busy(slave->sdev, task);
 	bif_slave_ctrl_unlock(slave);
 
 	return rc;
@@ -1258,16 +1565,29 @@
 }
 EXPORT_SYMBOL(bif_ctrl_put);
 
+static bool bif_slave_object_match(const struct bif_object *object,
+		const struct bif_match_criteria *criteria)
+{
+	return (object->type == criteria->obj_type)
+		&& (object->version == criteria->obj_version
+			|| !(criteria->match_mask & BIF_MATCH_OBJ_VERSION))
+		&& (object->manufacturer_id == criteria->obj_manufacturer_id
+		    || !(criteria->match_mask & BIF_MATCH_OBJ_MANUFACTURER_ID));
+}
+
 /*
  * Returns true if all parameters are matched, otherwise false.
  * function_type and function_version mean that their exists some function in
  * the slave which has the specified type and subtype.  ctrl == NULL is treated
  * as a wildcard.
  */
-static bool bif_slave_match(const struct bif_ctrl *ctrl,
+static bool bif_slave_match(struct bif_ctrl *ctrl,
 	struct bif_slave_dev *sdev, const struct bif_match_criteria *criteria)
 {
 	int i, type, version;
+	struct bif_object *object;
+	bool function_found = false;
+	bool object_found = false;
 
 	if (ctrl && (ctrl->bdev != sdev->bdev))
 		return false;
@@ -1295,10 +1615,29 @@
 			if (type == criteria->function_type &&
 				(version == criteria->function_version
 					|| !(criteria->match_mask
-						& BIF_MATCH_FUNCTION_VERSION)))
-				return true;
+					       & BIF_MATCH_FUNCTION_VERSION))) {
+				function_found = true;
+				break;
+			}
 		}
-		return false;
+		if (!function_found)
+			return false;
+	}
+
+	if (criteria->match_mask & BIF_MATCH_OBJ_TYPE) {
+		if (!sdev->nvm_function)
+			return false;
+		bif_ctrl_lock(ctrl);
+		list_for_each_entry(object, &sdev->nvm_function->object_list,
+					list) {
+			if (bif_slave_object_match(object, criteria)) {
+				object_found = true;
+				break;
+			}
+		}
+		bif_ctrl_unlock(ctrl);
+		if (!object_found)
+			return false;
 	}
 
 	return true;
@@ -1311,7 +1650,7 @@
  * @ctrl:		BIF controller consumer handle
  * @match_criteria:	Matching criteria used to filter slaves
  */
-int bif_slave_match_count(const struct bif_ctrl *ctrl,
+int bif_slave_match_count(struct bif_ctrl *ctrl,
 			const struct bif_match_criteria *match_criteria)
 {
 	struct bif_slave_dev *sdev;
@@ -1342,7 +1681,7 @@
  *
  * Returns a BIF slave handle if successful or an ERR_PTR if not.
  */
-struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
 	unsigned int id, const struct bif_match_criteria *match_criteria)
 {
 	struct bif_slave_dev *sdev;
@@ -1431,6 +1770,511 @@
 }
 EXPORT_SYMBOL(bif_slave_find_function);
 
+static bool bif_object_match(const struct bif_object *object,
+		const struct bif_obj_match_criteria *criteria)
+{
+	return (object->type == criteria->type
+			|| !(criteria->match_mask & BIF_OBJ_MATCH_TYPE))
+		&& (object->version == criteria->version
+			|| !(criteria->match_mask & BIF_OBJ_MATCH_VERSION))
+		&& (object->manufacturer_id == criteria->manufacturer_id
+		    || !(criteria->match_mask & BIF_OBJ_MATCH_MANUFACTURER_ID));
+}
+
+/**
+ * bif_object_match_count() - returns the number of objects associated with the
+ *			specified BIF slave which fit the matching criteria
+ * @slave:		BIF slave handle
+ * @match_criteria:	Matching criteria used to filter objects
+ */
+int bif_object_match_count(struct bif_slave *slave,
+			const struct bif_obj_match_criteria *match_criteria)
+{
+	struct bif_object *object;
+	int count = 0;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	if (!slave->sdev->nvm_function)
+		return 0;
+
+	bif_slave_ctrl_lock(slave);
+	list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
+			    list) {
+		if (bif_object_match(object, match_criteria))
+			count++;
+	}
+	bif_slave_ctrl_unlock(slave);
+
+	return count;
+}
+EXPORT_SYMBOL(bif_object_match_count);
+
+/**
+ * bif_object_match_get() - get a BIF object handle for the id'th object found
+ *			in the non-volatile memory of the specified BIF slave
+ *			which fits the matching criteria
+ * @slave:		BIF slave handle
+ * @id:			Index into the set of matching objects
+ * @match_criteria:	Matching criteria used to filter objects
+ *
+ * id must be in range [0, bif_object_match_count(slave, match_criteria) - 1].
+ *
+ * Returns a BIF object handle if successful or an ERR_PTR if not.  This handle
+ * must be freed using bif_object_put() when it is no longer needed.
+ */
+struct bif_object *bif_object_match_get(struct bif_slave *slave,
+	unsigned int id, const struct bif_obj_match_criteria *match_criteria)
+{
+	struct bif_object *object;
+	struct bif_object *object_found = NULL;
+	struct bif_object *object_consumer = ERR_PTR(-ENODEV);
+	int count = 0;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
+		pr_err("Invalid pointer input.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (!slave->sdev->nvm_function)
+		return object_consumer;
+
+	bif_slave_ctrl_lock(slave);
+	list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
+			    list) {
+		if (bif_object_match(object, match_criteria))
+			count++;
+		if (count == id + 1) {
+			object_found = object;
+			break;
+		}
+	}
+
+	if (object_found) {
+		object_consumer = kmemdup(object_found,
+					sizeof(*object_consumer), GFP_KERNEL);
+		if (!object_consumer) {
+			pr_err("out of memory\n");
+			object_consumer = ERR_PTR(-ENOMEM);
+			goto done;
+		}
+
+		object_consumer->data = kmemdup(object_found->data,
+					  object_found->length - 8, GFP_KERNEL);
+		if (!object_consumer->data) {
+			pr_err("out of memory\n");
+			kfree(object_consumer);
+			object_consumer = ERR_PTR(-ENOMEM);
+			goto done;
+		}
+
+		/*
+		 * Use prev pointer in consumer struct to point to original
+		 * struct in the internal linked list.
+		 */
+		object_consumer->list.prev = &object_found->list;
+	}
+
+done:
+	bif_slave_ctrl_unlock(slave);
+
+	return object_consumer;
+
+}
+EXPORT_SYMBOL(bif_object_match_get);
+
+/**
+ * bif_object_put() - frees the memory allocated for a BIF object pointer
+ *			returned by bif_object_match_get()
+ * @object:		BIF object to free
+ */
+void bif_object_put(struct bif_object *object)
+{
+	if (object)
+		kfree(object->data);
+	kfree(object);
+}
+EXPORT_SYMBOL(bif_object_put);
+
+/* Copies the contents of object into buf following MIPI-BIF formatting. */
+static void bif_object_flatten(u8 *buf, const struct bif_object *object)
+{
+	buf[0]			= object->type;
+	buf[1]			= object->version;
+	buf[2]			= object->manufacturer_id >> 8;
+	buf[3]			= object->manufacturer_id;
+	buf[4]			= object->length >> 8;
+	buf[5]			= object->length;
+	memcpy(&buf[6], object->data, object->length - 8);
+	buf[object->length - 2]	= object->crc >> 8;
+	buf[object->length - 1]	= object->crc;
+}
+
+/**
+ * bif_object_write() - writes a new BIF object at the end of the object list in
+ *			the non-volatile memory of a slave
+ * @slave:		BIF slave handle
+ * @type:		Type of the object
+ * @version:		Version of the object
+ * @manufacturer_id:	Manufacturer ID number allocated by MIPI
+ * @data:		Data contained in the object
+ * @data_len:		Length of the data
+ *
+ * Returns 0 on success or errno on failure.  This function will fail if the NVM
+ * lock points to an offset after the BIF object list terminator (0x00).
+ */
+int bif_object_write(struct bif_slave *slave, u8 type, u8 version,
+			u16 manufacturer_id, const u8 *data, int data_len)
+{
+	struct bif_object *object;
+	struct bif_object *tail_object;
+	struct bif_nvm_function	*nvm;
+	int rc;
+	int add_null = 0;
+	u16 offset = 0;
+	u8 *buf;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(data)) {
+		pr_err("Invalid input pointer\n");
+		return -EINVAL;
+	}
+
+	nvm = slave->sdev->nvm_function;
+	if (!nvm) {
+		pr_err("BIF slave has no NVM function\n");
+		return -ENODEV;
+	}
+
+	bif_slave_ctrl_lock(slave);
+	if (nvm->object_count > 0) {
+		tail_object = list_entry(nvm->object_list.prev,
+					struct bif_object, list);
+		offset = tail_object->addr - nvm->nvm_base_address
+				+ tail_object->length;
+	}
+
+	if (offset < nvm->nvm_lock_offset) {
+		pr_err("Cannot write BIF object to NVM because the end of the object list is locked (end=%d < lock=%d)\n",
+			offset, nvm->nvm_lock_offset);
+		rc = -EPERM;
+		goto error_unlock;
+	} else if (offset + data_len + 8 > nvm->nvm_size) {
+		pr_err("Cannot write BIF object to NVM because there is not enough remaining space (size=%d > remaining=%d)\n",
+			data_len + 8, nvm->nvm_size - offset);
+		rc = -EINVAL;
+		goto error_unlock;
+	}
+
+	if (offset + data_len + 8 < nvm->nvm_size)
+		add_null = 1;
+	object = kzalloc(sizeof(*object), GFP_KERNEL);
+	if (!object) {
+		pr_err("kzalloc failed\n");
+		rc = -ENOMEM;
+		goto error_unlock;
+	}
+
+	object->data = kzalloc(data_len, GFP_KERNEL);
+	if (!object->data) {
+		pr_err("kzalloc failed\n");
+		rc = -ENOMEM;
+		goto free_object;
+	}
+
+	buf = kzalloc(data_len + 8 + add_null, GFP_KERNEL);
+	if (!buf) {
+		pr_err("kzalloc failed\n");
+		rc = -ENOMEM;
+		goto free_data;
+	}
+
+	object->type		= type;
+	object->version		= version;
+	object->manufacturer_id	= manufacturer_id;
+	object->length		= data_len + 8;
+	memcpy(object->data, data, data_len);
+	object->crc		= bif_object_crc_ccitt(object);
+	object->addr		= offset + nvm->nvm_base_address;
+
+	bif_object_flatten(buf, object);
+	if (add_null)
+		buf[object->length] = BIF_OBJ_END_OF_LIST;
+
+	rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf,
+					object->length + add_null);
+	if (rc < 0) {
+		pr_err("NVM write failed, rc=%d\n", rc);
+		kfree(buf);
+		goto free_data;
+	}
+	kfree(buf);
+
+	list_add_tail(&object->list, &nvm->object_list);
+	nvm->object_count++;
+
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+
+free_data:
+	kfree(object->data);
+free_object:
+	kfree(object);
+error_unlock:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(bif_object_write);
+
+/*
+ * Returns a pointer to the internal object referenced by a consumer object
+ * if it exists.  Returns NULL if the internal object cannot be found.
+ */
+static struct bif_object *bif_object_consumer_search(
+	struct bif_nvm_function *nvm, const struct bif_object *consumer_object)
+{
+	struct bif_object *object = NULL;
+	struct bif_object *search_object;
+
+	/*
+	 * Internal struct in object linked list is pointed to by consumer
+	 * object list.prev.
+	 */
+	search_object = list_entry(consumer_object->list.prev,
+					struct bif_object, list);
+
+	list_for_each_entry(object, &nvm->object_list, list) {
+		if (object == search_object)
+			break;
+	}
+
+	if (object != search_object)
+		return NULL;
+
+	return object;
+}
+
+/**
+ * bif_object_overwrite() - overwrites an existing BIF object found in the
+ *			non-volatile memory of a slave
+ * @slave:		BIF slave handle
+ * @object:		Existing object in the slave to overwrite
+ * @type:		Type of the object
+ * @version:		Version of the object
+ * @manufacturer_id:	Manufacturer ID number allocated by MIPI
+ * @data:		Data contained in the object
+ * @data_len:		Length of the data
+ *
+ * Returns 0 on success or errno on failure.  The data stored within 'object'
+ * is updated to the new values upon success.  The new data written to the
+ * object must have exactly the same length as the old data (i.e.
+ * data_len == object->length - 8).
+ *
+ * This function will fail if the NVM lock points to an offset after the
+ * beginning of the existing BIF object.
+ */
+int bif_object_overwrite(struct bif_slave *slave,
+	struct bif_object *object, u8 type, u8 version,
+	u16 manufacturer_id, const u8 *data, int data_len)
+{
+	struct bif_object *edit_object = NULL;
+	struct bif_nvm_function *nvm;
+	int rc;
+	u16 crc;
+	u8 *buf;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)
+	    || IS_ERR_OR_NULL(data)) {
+		pr_err("Invalid input pointer\n");
+		return -EINVAL;
+	}
+
+	nvm = slave->sdev->nvm_function;
+	if (!nvm) {
+		pr_err("BIF slave has no NVM function\n");
+		return -ENODEV;
+	}
+
+	if (data_len + 8 != object->length) {
+		pr_err("New data length=%d is different from existing length=%d\n",
+			data_len, object->length - 8);
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	edit_object = bif_object_consumer_search(nvm, object);
+	if (!edit_object) {
+		pr_err("BIF object not found within slave\n");
+		rc = -EINVAL;
+		goto error_unlock;
+	}
+
+	if (edit_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
+		pr_err("Cannot overwrite BIF object in NVM because some portion of it is locked\n");
+		rc = -EPERM;
+		goto error_unlock;
+	}
+
+	buf = kzalloc(data_len + 8, GFP_KERNEL);
+	if (!buf) {
+		pr_err("kzalloc failed\n");
+		rc = -ENOMEM;
+		goto error_unlock;
+	}
+
+	buf[0]			= type;
+	buf[1]			= version;
+	buf[2]			= manufacturer_id >> 8;
+	buf[3]			= manufacturer_id;
+	buf[4]			= (data_len + 8) >> 8;
+	buf[5]			= data_len + 8;
+	memcpy(&buf[6], data, data_len);
+	crc			= bif_crc_ccitt(buf, data_len + 6);
+	buf[data_len + 6]	= crc >> 8;
+	buf[data_len + 7]	= crc;
+
+	rc = _bif_slave_nvm_raw_write(slave->sdev,
+		object->addr - nvm->nvm_base_address, buf, data_len + 8);
+	if (rc < 0) {
+		pr_err("NVM write failed, rc=%d\n", rc);
+		kfree(buf);
+		goto error_unlock;
+	}
+	kfree(buf);
+
+	/* Update internal object struct. */
+	edit_object->type		= type;
+	edit_object->version		= version;
+	edit_object->manufacturer_id	= manufacturer_id;
+	edit_object->length		= data_len + 8;
+	memcpy(edit_object->data, data, data_len);
+	edit_object->crc		= crc;
+
+	/* Update consumer object struct. */
+	object->type			= type;
+	object->version			= version;
+	object->manufacturer_id		= manufacturer_id;
+	object->length			= data_len + 8;
+	memcpy(object->data, data, data_len);
+	object->crc			= crc;
+
+error_unlock:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_object_overwrite);
+
+/**
+ * bif_object_delete() - deletes an existing BIF object found in the
+ *			non-volatile memory of a slave.  Objects found in the
+ *			object list in the NVM of the slave are shifted forward
+ *			in order to fill the hole left by the deleted object
+ * @slave:		BIF slave handle
+ * @object:		Existing object in the slave to delete
+ *
+ * Returns 0 on success or errno on failure.  bif_object_put() must still be
+ * called after this function in order to free the memory in the consumer
+ * 'object' struct pointer.
+ *
+ * This function will fail if the NVM lock points to an offset after the
+ * beginning of the existing BIF object.
+ */
+int bif_object_delete(struct bif_slave *slave, const struct bif_object *object)
+{
+	struct bif_object *del_object = NULL;
+	struct bif_object *tail_object;
+	struct bif_nvm_function *nvm;
+	bool found = false;
+	int pos = 0;
+	int rc;
+	u8 *buf;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)) {
+		pr_err("Invalid input pointer\n");
+		return -EINVAL;
+	}
+
+	nvm = slave->sdev->nvm_function;
+	if (!nvm) {
+		pr_err("BIF slave has no NVM function\n");
+		return -ENODEV;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	del_object = bif_object_consumer_search(nvm, object);
+	if (!del_object) {
+		pr_err("BIF object not found within slave\n");
+		rc = -EINVAL;
+		goto error_unlock;
+	}
+
+	if (del_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
+		pr_err("Cannot delete BIF object in NVM because some portion of it is locked\n");
+		rc = -EPERM;
+		goto error_unlock;
+	}
+
+	buf = kmalloc(nvm->nvm_size, GFP_KERNEL);
+	if (!buf) {
+		pr_err("kzalloc failed\n");
+		rc = -ENOMEM;
+		goto error_unlock;
+	}
+
+	/*
+	 * Copy the contents of objects after the one to be deleted into a flat
+	 * array.
+	 */
+	list_for_each_entry(tail_object, &nvm->object_list, list) {
+		if (found) {
+			bif_object_flatten(&buf[pos], tail_object);
+			pos += tail_object->length;
+		} else if (tail_object == del_object) {
+			found = true;
+		}
+	}
+
+	/* Add the list terminator. */
+	buf[pos++] = BIF_OBJ_END_OF_LIST;
+
+	rc = _bif_slave_nvm_raw_write(slave->sdev,
+		del_object->addr - nvm->nvm_base_address, buf, pos);
+	if (rc < 0) {
+		pr_err("NVM write failed, rc=%d\n", rc);
+		kfree(buf);
+		goto error_unlock;
+	}
+	kfree(buf);
+
+	/* Update the addresses of the objects after the one to be deleted. */
+	found = false;
+	list_for_each_entry(tail_object, &nvm->object_list, list) {
+		if (found)
+			tail_object->addr -= del_object->length;
+		else if (tail_object == del_object)
+			found = true;
+	}
+
+	list_del(&del_object->list);
+	kfree(del_object->data);
+	kfree(del_object);
+	nvm->object_count--;
+
+error_unlock:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_object_delete);
+
 /**
  * bif_slave_read() - read contiguous memory values from a BIF slave
  * @slave:	BIF slave handle
@@ -1492,6 +2336,74 @@
 EXPORT_SYMBOL(bif_slave_write);
 
 /**
+ * bif_slave_nvm_raw_read() - read contiguous memory values from a BIF slave's
+ *		non-volatile memory (NVM)
+ * @slave:	BIF slave handle
+ * @offset:	Offset from the beginning of BIF slave NVM to begin reading at
+ * @buf:	Buffer to fill with memory values
+ * @len:	Number of byte to read
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
+				int len)
+{
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+		return -EINVAL;
+	} else if (IS_ERR_OR_NULL(buf)) {
+		pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
+		return -EINVAL;
+	} else if (!slave->sdev->nvm_function) {
+		pr_err("BIF slave has no NVM function\n");
+		return -ENODEV;
+	} else if (offset + len > slave->sdev->nvm_function->nvm_size) {
+		pr_err("read offset + len = %d > NVM size = %d\n",
+			offset + len, slave->sdev->nvm_function->nvm_size);
+		return -EINVAL;
+	}
+
+	return bif_slave_read(slave,
+		slave->sdev->nvm_function->nvm_base_address + offset, buf, len);
+}
+EXPORT_SYMBOL(bif_slave_nvm_raw_read);
+
+/**
+ * bif_slave_nvm_raw_write() - write contiguous memory values to a BIF slave's
+ *		non-volatile memory (NVM)
+ * @slave:	BIF slave handle
+ * @offset:	Offset from the beginning of BIF slave NVM to begin writing at
+ * @buf:	Buffer containing values to write
+ * @len:	Number of byte to write
+ *
+ * Note that this function does *not* respect the MIPI-BIF object data
+ * formatting specification.  It can cause corruption of the object data list
+ * stored in NVM if used improperly.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
+				int len)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+		return -EINVAL;
+	} else if (IS_ERR_OR_NULL(buf)) {
+		pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+	rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf, len);
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_slave_nvm_raw_write);
+
+/**
  * bif_slave_is_present() - check if a slave is currently physically present
  *		in the system
  * @slave:	BIF slave handle
@@ -2032,45 +2944,6 @@
 	return rc;
 }
 
-/**
- * bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
- * @buffer:	Data to calculate the CRC of
- * @len:	Length of the data buffer in bytes
- *
- * MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects.  This
- * function performs the CRC calculation while taking into account the bit
- * ordering used by BIF.
- */
-u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
-{
-	u16 crc = 0xFFFF;
-
-	while (len--) {
-		crc = crc_ccitt_byte(crc, bitrev8(*buffer));
-		buffer++;
-	}
-	return bitrev16(crc);
-}
-EXPORT_SYMBOL(bif_crc_ccitt);
-
-static u16 bif_object_crc_ccitt(const struct bif_object *object)
-{
-	u16 crc = 0xFFFF;
-	int i;
-
-	crc = crc_ccitt_byte(crc, bitrev8(object->type));
-	crc = crc_ccitt_byte(crc, bitrev8(object->version));
-	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
-	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
-	crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
-	crc = crc_ccitt_byte(crc, bitrev8(object->length));
-
-	for (i = 0; i < object->length - 8; i++)
-		crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));
-
-	return bitrev16(crc);
-}
-
 /*
  * Check if the specified function is an NVM function and if it is, then
  * instantiate NVM function data for the slave and read all objects.
@@ -2079,7 +2952,7 @@
 		struct bif_ddb_l2_data *func)
 {
 	int rc = 0;
-	int data_len;
+	int data_len, read_size;
 	u8 buf[8], object_type;
 	struct bif_object *object;
 	struct bif_object *temp;
@@ -2109,12 +2982,21 @@
 		return rc;
 	}
 
-	sdev->nvm_function->nvm_pointer		= buf[0] << 8 | buf[1];
+	sdev->nvm_function->nvm_pointer			= buf[0] << 8 | buf[1];
 	sdev->nvm_function->slave_control_channel	= buf[2];
 	sdev->nvm_function->write_buffer_size		= buf[3];
 	sdev->nvm_function->nvm_base_address		= buf[4] << 8 | buf[5];
 	sdev->nvm_function->nvm_size			= buf[6] << 8 | buf[7];
 
+	/* Read NVM lock offset */
+	rc = _bif_slave_read(sdev, sdev->nvm_function->nvm_pointer, buf, 2);
+	if (rc) {
+		pr_err("Slave memory read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev->nvm_function->nvm_lock_offset		= buf[0] << 8 | buf[1];
+
 	INIT_LIST_HEAD(&sdev->nvm_function->object_list);
 
 	/* Read object list */
@@ -2125,8 +3007,7 @@
 		return rc;
 	}
 
-	/* Object type == 0x00 corresponds to the end of the object list. */
-	while (object_type != 0x00) {
+	while (object_type != BIF_OBJ_END_OF_LIST) {
 		object = kzalloc(sizeof(*object), GFP_KERNEL);
 		if (!object) {
 			pr_err("out of memory\n");
@@ -2178,15 +3059,20 @@
 			goto free_data;
 		}
 
-		rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, 3);
+		if ((object->length + addr) >= (sdev->nvm_function->nvm_size
+				+ sdev->nvm_function->nvm_base_address))
+			read_size = 2;
+		else
+			read_size = 3;
+		rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, read_size);
 		if (rc) {
 			pr_err("Slave memory read of object CRC failed; addr=0x%04X, len=%d, rc=%d\n",
-				addr + 6 + data_len, 3, rc);
+				addr + 6 + data_len, read_size, rc);
 			goto free_data;
 		}
 
 		object->crc = buf[0] << 8 | buf[1];
-		object_type = buf[2];
+		object_type = (read_size == 3) ? buf[2] : BIF_OBJ_END_OF_LIST;
 		sdev->nvm_function->object_count++;
 
 		crc = bif_object_crc_ccitt(object);
@@ -2336,6 +3222,12 @@
 			} else if (rc == 1) {
 				sdev->present = true;
 				sdev->bdev->selected_sdev = sdev;
+				rc = bif_parse_slave_data(sdev);
+				if (rc) {
+					pr_err("Failed to parse secondary slave data, rc=%d\n",
+						rc);
+					goto free_slave;
+				}
 			} else {
 				sdev->present = false;
 				sdev->bdev->selected_sdev = NULL;
@@ -2459,6 +3351,11 @@
 			sdev->present = true;
 			sdev->bdev->selected_sdev = sdev;
 			rc = bif_parse_slave_data(sdev);
+			if (rc) {
+				pr_err("Failed to parse secondary slave data, rc=%d\n",
+					rc);
+				return rc;
+			}
 		} else {
 			pr_err("Slave failed to respond to DILC bus command; its UID is thus unverified.\n");
 			sdev->unique_id_bits_known = 0;
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
index 19a560a..e3f7d2f 100644
--- a/drivers/bif/qpnp-bsi.c
+++ b/drivers/bif/qpnp-bsi.c
@@ -170,7 +170,7 @@
 #define QPNP_BSI_DEFAULT_VID_REF_UV	1800000
 
 /* These have units of tau_bif. */
-#define QPNP_BSI_MAX_TRANSMIT_CYCLES	36
+#define QPNP_BSI_MAX_TRANSMIT_CYCLES	46
 #define QPNP_BSI_MIN_RECEIVE_CYCLES	24
 #define QPNP_BSI_MAX_BUS_QUERY_CYCLES	17
 
@@ -544,12 +544,6 @@
 	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
 	int rc;
 
-	rc = qpnp_bsi_clear_bsi_error(chip);
-	if (rc)
-		return rc;
-
-	qpnp_bsi_clear_irq_flags(chip);
-
 	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
 
 	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -563,6 +557,12 @@
 	if (rc)
 		return rc;
 
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
 	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
 	if (rc)
 		return rc;
@@ -578,12 +578,6 @@
 	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
 	int rc, timeout;
 
-	rc = qpnp_bsi_clear_bsi_error(chip);
-	if (rc)
-		return rc;
-
-	qpnp_bsi_clear_irq_flags(chip);
-
 	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
 
 	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -597,6 +591,12 @@
 	if (rc)
 		return rc;
 
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
 	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
 	if (rc)
 		return rc;
@@ -624,12 +624,6 @@
 	int rc, timeout;
 	u8 buf[3];
 
-	rc = qpnp_bsi_clear_bsi_error(chip);
-	if (rc)
-		return rc;
-
-	qpnp_bsi_clear_irq_flags(chip);
-
 	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
 
 	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -643,6 +637,12 @@
 	if (rc)
 		return rc;
 
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
 	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
 	if (rc)
 		return rc;
@@ -826,10 +826,10 @@
 	/*
 	 * Send burst read length bus commands according to the following:
 	 *
-	 * 256                --> RBL0
-	 * 0-255 = 16 * y + x --> RBEy and RBLx
-	 *		RBE0 does not need to be sent
-	 *		RBL0 does not need to be sent
+	 * 1                     --> No RBE or RBL
+	 * 2  - 15  = x          --> RBLx
+	 * 16 - 255 = 16 * y + x --> RBEy and RBLx (RBL0 not sent)
+	 * 256                   --> RBL0
 	 */
 	if (burst_len == 256) {
 		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
@@ -851,7 +851,7 @@
 			return rc;
 	}
 
-	if (burst_len % 16) {
+	if (burst_len % 16 && burst_len > 1) {
 		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
 					BIF_CMD_RBL + (burst_len % 16));
 		if (rc)
@@ -906,12 +906,6 @@
 	int rc, rc2, i, burst_len;
 	u8 buf[3];
 
-	rc = qpnp_bsi_clear_bsi_error(chip);
-	if (rc)
-		return rc;
-
-	qpnp_bsi_clear_irq_flags(chip);
-
 	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
 
 	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -925,6 +919,12 @@
 	if (rc)
 		return rc;
 
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
 	while (len > 0) {
 		burst_len = min(len, 256);
 
@@ -1001,12 +1001,6 @@
 	unsigned long flags;
 	int rc, rc2, i;
 
-	rc = qpnp_bsi_clear_bsi_error(chip);
-	if (rc)
-		return rc;
-
-	qpnp_bsi_clear_irq_flags(chip);
-
 	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
 
 	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -1020,6 +1014,12 @@
 	if (rc)
 		return rc;
 
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
 	rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_ERA, addr >> 8);
 	if (rc)
 		return rc;
@@ -1075,12 +1075,6 @@
 	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
 	int rc;
 
-	rc = qpnp_bsi_clear_bsi_error(chip);
-	if (rc)
-		return rc;
-
-	qpnp_bsi_clear_irq_flags(chip);
-
 	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
 
 	/*
@@ -1105,6 +1099,12 @@
 	 */
 	chip->state = BIF_BUS_STATE_INTERRUPT;
 
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
 	/* Send EINT bus command. */
 	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, BIF_TRANS_BC,
 							BIF_CMD_EINT);
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/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index c726694..81a90fe 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -79,6 +79,7 @@
 	uint8_t		first_blk;
 	uint8_t		last_blk;
 	uint8_t		authkey[QCEDEV_MAX_SHA_BLOCK_SIZE];
+	bool		init_done;
 };
 
 struct qcedev_async_req {
@@ -744,6 +745,7 @@
 			sha_ctxt->diglen = SHA256_DIGEST_SIZE;
 		}
 	}
+	sha_ctxt->init_done = true;
 	return 0;
 }
 
@@ -878,6 +880,11 @@
 	int num_entries = 0;
 	uint32_t total = 0;
 
+	if (handle->sha_ctxt.init_done == false) {
+		pr_err("%s Init was not called\n", __func__);
+		return -EINVAL;
+	}
+
 	/* verify address src(s) */
 	for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
 		if (!access_ok(VERIFY_READ,
@@ -985,10 +992,19 @@
 	int err = 0;
 	struct scatterlist sg_src;
 	uint32_t total;
-
 	uint8_t *k_buf_src = NULL;
 	uint8_t *k_align_src = NULL;
 
+	if (handle->sha_ctxt.init_done == false) {
+		pr_err("%s Init was not called\n", __func__);
+		return -EINVAL;
+	}
+
+	if (handle->sha_ctxt.trailing_buf_len == 0) {
+		pr_err("%s Incorrect trailng buffer %d\n", __func__,
+					handle->sha_ctxt.trailing_buf_len);
+		return -EINVAL;
+	}
 	handle->sha_ctxt.last_blk = 1;
 
 	total = handle->sha_ctxt.trailing_buf_len;
@@ -1019,6 +1035,7 @@
 	handle->sha_ctxt.auth_data[0] = 0;
 	handle->sha_ctxt.auth_data[1] = 0;
 	handle->sha_ctxt.trailing_buf_len = 0;
+	handle->sha_ctxt.init_done = false;
 	memset(&handle->sha_ctxt.trailing_buf[0], 0, 64);
 
 	kfree(k_buf_src);
@@ -1413,12 +1430,37 @@
 			return -EFAULT;
 
 	/* Verify Destination Address's */
-	if (areq->cipher_op_req.in_place_op != 1)
-		for (i = 0; i < areq->cipher_op_req.entries; i++)
-			if (!access_ok(VERIFY_READ,
-			(void __user *)areq->cipher_op_req.vbuf.dst[i].vaddr,
-					areq->cipher_op_req.vbuf.dst[i].len))
-				return -EFAULT;
+	if (creq->in_place_op != 1) {
+		for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) {
+			if ((areq->cipher_op_req.vbuf.dst[i].vaddr != 0) &&
+						(total < creq->data_len)) {
+				if (!access_ok(VERIFY_WRITE,
+					(void __user *)creq->vbuf.dst[i].vaddr,
+						creq->vbuf.dst[i].len)) {
+					pr_err("%s:DST WR_VERIFY err %d=0x%x\n",
+						__func__, i,
+						(u32)creq->vbuf.dst[i].vaddr);
+					return -EFAULT;
+				}
+				total += creq->vbuf.dst[i].len;
+			}
+		}
+	} else  {
+		for (i = 0, total = 0; i < creq->entries; i++) {
+			if (total < creq->data_len) {
+				if (!access_ok(VERIFY_WRITE,
+					(void __user *)creq->vbuf.src[i].vaddr,
+						creq->vbuf.src[i].len)) {
+					pr_err("%s:SRC WR_VERIFY err %d=0x%x\n",
+						__func__, i,
+						(u32)creq->vbuf.src[i].vaddr);
+					return -EFAULT;
+				}
+				total += creq->vbuf.src[i].len;
+			}
+		}
+	}
+	total = 0;
 
 	if (areq->cipher_op_req.mode == QCEDEV_AES_MODE_CTR)
 		byteoffset = areq->cipher_op_req.byteoffset;
@@ -1619,6 +1661,9 @@
 static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
 						struct qcedev_control *podev)
 {
+	uint32_t total = 0;
+	uint32_t i;
+
 	if (req->use_pmem) {
 		pr_err("%s: Use of PMEM is not supported\n", __func__);
 		goto error;
@@ -1670,7 +1715,22 @@
 			goto error;
 		}
 	}
-
+	/* Check for sum of all dst length is equal to data_len  */
+	for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++)
+		total += req->vbuf.dst[i].len;
+	if (total != req->data_len) {
+		pr_err("%s: Total (i=%d) dst(%d) buf size != data_len (%d)\n",
+			__func__, i, total, req->data_len);
+		goto error;
+	}
+	/* Check for sum of all src length is equal to data_len  */
+	for (i = 0, total = 0; i < req->entries; i++)
+		total += req->vbuf.src[i].len;
+	if (total != req->data_len) {
+		pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
+			__func__, total, req->data_len);
+		goto error;
+	}
 	return 0;
 error:
 	return -EINVAL;
@@ -1680,6 +1740,9 @@
 static int qcedev_check_sha_params(struct qcedev_sha_op_req *req,
 						struct qcedev_control *podev)
 {
+	uint32_t total = 0;
+	uint32_t i;
+
 	if ((req->alg == QCEDEV_ALG_AES_CMAC) &&
 				(!podev->ce_support.cmac)) {
 		pr_err("%s: CMAC not supported\n", __func__);
@@ -1717,6 +1780,14 @@
 		}
 	}
 
+	/* Check for sum of all src length is equal to data_len  */
+	for (i = 0, total = 0; i < req->entries; i++)
+		total += req->data[i].len;
+	if (total != req->data_len) {
+		pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
+			__func__, total, req->data_len);
+		goto sha_error;
+	}
 	return 0;
 sha_error:
 	return -EINVAL;
@@ -1805,6 +1876,7 @@
 					sizeof(struct qcedev_sha_op_req)))
 				return -EFAULT;
 		}
+		handle->sha_ctxt.init_done = true;
 		break;
 	case QCEDEV_IOCTL_GET_CMAC_REQ:
 		if (!podev->ce_support.cmac)
@@ -1829,6 +1901,10 @@
 			if (err)
 				return err;
 		} else {
+			if (handle->sha_ctxt.init_done == false) {
+				pr_err("%s Init was not called\n", __func__);
+				return -EINVAL;
+			}
 			err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
 			if (err)
 				return err;
@@ -1845,6 +1921,10 @@
 
 	case QCEDEV_IOCTL_SHA_FINAL_REQ:
 
+		if (handle->sha_ctxt.init_done == false) {
+			pr_err("%s Init was not called\n", __func__);
+			return -EINVAL;
+		}
 		if (!access_ok(VERIFY_WRITE, (void __user *)arg,
 				sizeof(struct qcedev_sha_op_req)))
 			return -EFAULT;
@@ -1866,6 +1946,7 @@
 		if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
 					sizeof(struct qcedev_sha_op_req)))
 			return -EFAULT;
+		handle->sha_ctxt.init_done = false;
 		break;
 
 	case QCEDEV_IOCTL_GET_SHA_REQ:
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 415c73e..90451ca 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -136,10 +136,28 @@
 	buf = __ion_secure_cma_allocate(heap, buffer, len, align, flags);
 
 	if (buf) {
+		int ret;
+
 		buf->secure.want_delayed_unsecure = 0;
 		atomic_set(&buf->secure.secure_cnt, 0);
 		mutex_init(&buf->secure.lock);
 		buf->secure.is_secure = 1;
+		buf->secure.ignore_check = true;
+
+		/*
+		 * make sure the size is set before trying to secure
+		 */
+		buffer->size = len;
+		ret = ion_cp_secure_buffer(buffer, ION_CP_V2, 0, 0);
+		if (ret) {
+			/*
+			 * Don't treat the secure buffer failing here as an
+			 * error for backwards compatibility reasons. If
+			 * the secure fails, the map will also fail so there
+			 * is no security risk.
+			 */
+			pr_debug("%s: failed to secure buffer\n", __func__);
+		}
 		return 0;
 	} else {
 		return -ENOMEM;
@@ -153,6 +171,8 @@
 	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
 
 	dev_dbg(dev, "Release buffer %p\n", buffer);
+
+	ion_cp_unsecure_buffer(buffer, 1);
 	/* release memory */
 	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
 	sg_free_table(info->table);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index d315fc4..7ffab09 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -286,7 +286,7 @@
 		goto out_unlock;
 	}
 
-	if (atomic_read(&buf->secure_cnt)) {
+	if (atomic_read(&buf->secure_cnt) && !buf->ignore_check) {
 		if (buf->version != version || buf->data != data) {
 			pr_err("%s: Trying to re-secure buffer with different values",
 				__func__);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/gpu/ion/msm/ion_cp_common.h
index 8ae19be..ded6af9 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.h
+++ b/drivers/gpu/ion/msm/ion_cp_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,10 @@
 	struct mutex lock;
 	int version;
 	void *data;
+	/*
+	 * secure is happening at allocation time, ignore version/data check
+	 */
+	bool ignore_check;
 };
 
 #if defined(CONFIG_ION_MSM)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index cdf711c..79fbd2c 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -632,11 +632,11 @@
 
 	kgsl_mmu_unmap(pagetable, &device->memstore);
 
-	kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
-
 	kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
 
 	kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory);
+
+	kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
 }
 
 static int adreno_setup_pt(struct kgsl_device *device,
@@ -648,6 +648,12 @@
 
 	result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc);
 
+	/*
+	 * ALERT: Order of these mapping is important to
+	 * Keep the most used entries like memptrs, memstore
+	 * and mmu setstate memory by TLB prefetcher.
+	 */
+
 	if (!result)
 		result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
 
@@ -656,17 +662,16 @@
 
 	if (!result)
 		result = kgsl_mmu_map_global(pagetable,
-			&adreno_dev->profile.shared_buffer);
-
-	if (!result)
-		result = kgsl_mmu_map_global(pagetable,
 			&adreno_dev->pwron_fixup);
 
-
 	if (!result)
 		result = kgsl_mmu_map_global(pagetable,
 			&device->mmu.setstate_memory);
 
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&adreno_dev->profile.shared_buffer);
+
 	if (result) {
 		/* On error clean up what we have wrought */
 		adreno_cleanup_pt(device, pagetable);
@@ -678,8 +683,8 @@
 	 * For the IOMMU, this will be used to restrict access to the
 	 * mapped registers.
 	 */
-	device->mh.mpu_range = device->mmu.setstate_memory.gpuaddr +
-				device->mmu.setstate_memory.size;
+	device->mh.mpu_range = adreno_dev->profile.shared_buffer.gpuaddr +
+				adreno_dev->profile.shared_buffer.size;
 
 	return 0;
 }
@@ -1697,8 +1702,8 @@
 	/* 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;
@@ -3664,6 +3669,8 @@
 			}
 		}
 		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;
 		}
@@ -3725,8 +3732,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;
 }
 
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 6507852..a837574 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -63,7 +63,6 @@
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  NULL
 #endif
 
-void adreno_debugfs_init(struct kgsl_device *device);
 
 #define ADRENO_ISTORE_START 0x5000 /* Istore offset */
 
@@ -749,4 +748,11 @@
 		return ADRENO_REG_REGISTER_MAX;
 	return adreno_dev->gpudev->reg_offsets->offsets[offset_name];
 }
+
+#ifdef CONFIG_DEBUG_FS
+void adreno_debugfs_init(struct kgsl_device *device);
+#else
+static inline void adreno_debugfs_init(struct kgsl_device *device) { }
+#endif
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index fc98d86..a7d1b7f 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -23,8 +23,6 @@
 
 #include "a2xx_reg.h"
 
-unsigned int kgsl_cff_dump_enable;
-
 DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
 			kgsl_cff_dump_enable_set, "%llu\n");
 
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_profile.h b/drivers/gpu/msm/adreno_profile.h
index d91b09b..7e1ccb2 100644
--- a/drivers/gpu/msm/adreno_profile.h
+++ b/drivers/gpu/msm/adreno_profile.h
@@ -61,6 +61,7 @@
 #define ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS  (ADRENO_PROFILE_LOG_BUF_SIZE / \
 						sizeof(unsigned int))
 
+#ifdef CONFIG_DEBUG_FS
 void adreno_profile_init(struct kgsl_device *device);
 void adreno_profile_close(struct kgsl_device *device);
 int adreno_profile_process_results(struct kgsl_device *device);
@@ -70,6 +71,22 @@
 void adreno_profile_postib_processing(struct kgsl_device *device,
 		unsigned int *cmd_flags, unsigned int **rbptr,
 		unsigned int *cmds_gpu);
+#else
+static inline void adreno_profile_init(struct kgsl_device *device) { }
+static inline void adreno_profile_close(struct kgsl_device *device) { }
+static inline int adreno_profile_process_results(struct kgsl_device *device)
+{
+	return 0;
+}
+
+static inline void adreno_profile_preib_processing(struct kgsl_device *device,
+		unsigned int context_id, unsigned int *cmd_flags,
+		unsigned int **rbptr, unsigned int *cmds_gpu) { }
+
+static inline void adreno_profile_postib_processing(struct kgsl_device *device,
+		unsigned int *cmd_flags, unsigned int **rbptr,
+		unsigned int *cmds_gpu) { }
+#endif
 
 static inline bool adreno_profile_enabled(struct adreno_profile *profile)
 {
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ceff923..8aec755 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1073,7 +1073,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 +1095,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 +1163,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 +1180,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 2781a34..298b36e 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -909,13 +909,12 @@
 
 	private = kgsl_find_process_private(cur_dev_priv);
 
+	if (!private)
+		return NULL;
+
 	mutex_lock(&private->process_private_mutex);
 
-	/*
-	 * If debug root initialized then it means the rest of the fields
-	 * are also initialized
-	 */
-	if (private->debug_root)
+	if (test_bit(KGSL_PROCESS_INIT, &private->priv))
 		goto done;
 
 	private->mem_rb = RB_ROOT;
@@ -936,6 +935,8 @@
 	if (kgsl_process_init_debugfs(private))
 		goto error;
 
+	set_bit(KGSL_PROCESS_INIT, &private->priv);
+
 done:
 	mutex_unlock(&private->process_private_mutex);
 	return private;
@@ -3051,7 +3052,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..0525eab 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -267,7 +267,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_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index b2f137c..fe9bc76 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-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
@@ -35,7 +35,7 @@
 static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
 static inline void kgsl_core_debugfs_close(void) { }
 static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
-static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
+static inline int kgsl_process_init_debugfs(struct kgsl_process_private *priv)
 {
 	return 0;
 }
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 09a31c9..0b5fe52 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -315,8 +315,23 @@
 	unsigned int pagefault_ts;
 };
 
+/**
+ * struct kgsl_process_private -  Private structure for a KGSL process (across
+ * all devices)
+ * @priv: Internal flags, use KGSL_PROCESS_* values
+ * @pid: ID for the task owner of the process
+ * @mem_lock: Spinlock to protect the process memory lists
+ * @refcount: kref object for reference counting the process
+ * @process_private_mutex: Mutex to synchronize access to the process struct
+ * @mem_rb: RB tree node for the memory owned by this process
+ * @idr: Iterator for assigning IDs to memory allocations
+ * @pagetable: Pointer to the pagetable owned by this process
+ * @kobj: Pointer to a kobj for the sysfs directory for this process
+ * @debug_root: Pointer to the debugfs root for this process
+ * @stats: Memory allocation statistics for this process
+ */
 struct kgsl_process_private {
-	unsigned int refcnt;
+	unsigned long priv;
 	pid_t pid;
 	spinlock_t mem_lock;
 
@@ -338,6 +353,14 @@
 	} stats[KGSL_MEM_ENTRY_MAX];
 };
 
+/**
+ * enum kgsl_process_priv_flags - Private flags for kgsl_process_private
+ * @KGSL_PROCESS_INIT: Set if the process structure has been set up
+ */
+enum kgsl_process_priv_flags {
+	KGSL_PROCESS_INIT = 0,
+};
+
 struct kgsl_device_private {
 	struct kgsl_device *device;
 	struct kgsl_process_private *process_priv;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index ecda5a7..a06ebbf 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -72,16 +72,18 @@
 
 static struct iommu_access_ops *iommu_access_ops;
 
-static void _iommu_lock(void)
+static void _iommu_lock(struct kgsl_iommu const *iommu)
 {
 	if (iommu_access_ops && iommu_access_ops->iommu_lock_acquire)
-		iommu_access_ops->iommu_lock_acquire();
+		iommu_access_ops->iommu_lock_acquire(
+						iommu->sync_lock_initialized);
 }
 
-static void _iommu_unlock(void)
+static void _iommu_unlock(struct kgsl_iommu const *iommu)
 {
 	if (iommu_access_ops && iommu_access_ops->iommu_lock_release)
-		iommu_access_ops->iommu_lock_release();
+		iommu_access_ops->iommu_lock_release(
+						iommu->sync_lock_initialized);
 }
 
 struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
@@ -906,6 +908,8 @@
 	return 0;
 }
 
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+
 /*
  * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
  * @mmu - Pointer to mmu device
@@ -973,6 +977,12 @@
 
 	return status;
 }
+#else
+static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
+{
+	return 0;
+}
+#endif
 
 /*
  * kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
@@ -1643,7 +1653,7 @@
 	 * changing pagetables we can use this lsb value of the pagetable w/o
 	 * having to read it again
 	 */
-	_iommu_lock();
+	_iommu_lock(iommu);
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
 		for (j = 0; j < iommu_unit->dev_count; j++) {
@@ -1682,7 +1692,7 @@
 		}
 	}
 	kgsl_iommu_lock_rb_in_tlb(mmu);
-	_iommu_unlock();
+	_iommu_unlock(iommu);
 
 	/* For complete CFF */
 	kgsl_cffdump_setmem(mmu->device, mmu->setstate_memory.gpuaddr +
@@ -1788,12 +1798,12 @@
 			for (j = 0; j < iommu_unit->dev_count; j++) {
 				if (iommu_unit->dev[j].fault) {
 					kgsl_iommu_enable_clk(mmu, j);
-					_iommu_lock();
+					_iommu_lock(iommu);
 					KGSL_IOMMU_SET_CTX_REG(iommu,
 						iommu_unit,
 						iommu_unit->dev[j].ctx_id,
 						RESUME, 1);
-					_iommu_unlock();
+					_iommu_unlock(iommu);
 					iommu_unit->dev[j].fault = 0;
 				}
 			}
@@ -1912,7 +1922,7 @@
 		kgsl_idle(mmu->device);
 
 	/* Acquire GPU-CPU sync Lock here */
-	_iommu_lock();
+	_iommu_lock(iommu);
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
 		if (!msm_soc_version_supports_iommu_v0())
@@ -1979,7 +1989,7 @@
 	}
 
 	/* Release GPU-CPU sync Lock here */
-	_iommu_unlock();
+	_iommu_unlock(iommu);
 
 	/* Disable smmu clock */
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index a7832e4..94649bd 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -13,8 +13,6 @@
 #ifndef __KGSL_LOG_H
 #define __KGSL_LOG_H
 
-extern unsigned int kgsl_cff_dump_enable;
-
 #define KGSL_LOG_INFO(dev, lvl, fmt, args...) \
 	do { \
 		if ((lvl) >= 6)  \
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index d850a0e..17127a8 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -40,8 +40,6 @@
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 
-#define D(x...) pr_info(x)
-
 #define I2C_RETRY_COUNT 10
 
 #define NEAR_DELAY_TIME ((100 * HZ) / 1000)
@@ -65,8 +63,6 @@
 #define CM36283_PS_MAX_POLL_DELAY	1000
 #define CM36283_PS_DEFAULT_POLL_DELAY	100
 
-static int record_init_fail = 0;
-
 static const int als_range[] = {
 	[CM36283_ALS_IT0] = 6554,
 	[CM36283_ALS_IT1] = 3277,
@@ -156,9 +152,8 @@
 static int I2C_RxData(uint16_t slaveAddr, uint8_t cmd, uint8_t *rxData, int length)
 {
 	uint8_t loop_i;
-	int val;
 	struct cm36283_info *lpi = lp_info;
-  uint8_t subaddr[1];
+	uint8_t subaddr[1];
 
 	struct i2c_msg msgs[] = {
 		{
@@ -174,24 +169,21 @@
 		 .buf = rxData,
 		 },		 
 	};
-  subaddr[0] = cmd;
+
+	subaddr[0] = cmd;
 
 	for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) {
 
 		if (i2c_transfer(lp_info->i2c_client->adapter, msgs, 2) > 0)
 			break;
 
-		val = gpio_get_value(lpi->intr_pin);
-		/*check intr GPIO when i2c error*/
-		if (loop_i == 0 || loop_i == I2C_RETRY_COUNT -1)
-			D("[PS][CM36283 error] %s, i2c err, slaveAddr 0x%x ISR gpio %d  = %d, record_init_fail %d \n",
-				__func__, slaveAddr, lpi->intr_pin, val, record_init_fail);
-
+		dev_err(&lpi->i2c_client->dev, "%s: I2C error(%d). Retrying.\n",
+				__func__, cmd);
 		msleep(10);
 	}
 	if (loop_i >= I2C_RETRY_COUNT) {
-		printk(KERN_ERR "[PS_ERR][CM36283 error] %s retry over %d\n",
-			__func__, I2C_RETRY_COUNT);
+		dev_err(&lpi->i2c_client->dev, "%s: Retry count exceeds %d.",
+				__func__, I2C_RETRY_COUNT);
 		return -EIO;
 	}
 
@@ -201,8 +193,8 @@
 static int I2C_TxData(uint16_t slaveAddr, uint8_t *txData, int length)
 {
 	uint8_t loop_i;
-	int val;
 	struct cm36283_info *lpi = lp_info;
+
 	struct i2c_msg msg[] = {
 		{
 		 .addr = slaveAddr,
@@ -216,18 +208,13 @@
 		if (i2c_transfer(lp_info->i2c_client->adapter, msg, 1) > 0)
 			break;
 
-		val = gpio_get_value(lpi->intr_pin);
-		/*check intr GPIO when i2c error*/
-		if (loop_i == 0 || loop_i == I2C_RETRY_COUNT -1)
-			D("[PS][CM36283 error] %s, i2c err, slaveAddr 0x%x, value 0x%x, ISR gpio%d  = %d, record_init_fail %d\n",
-				__func__, slaveAddr, txData[0], lpi->intr_pin, val, record_init_fail);
-
+		pr_err("%s: I2C error. Retrying...\n", __func__);
 		msleep(10);
 	}
 
 	if (loop_i >= I2C_RETRY_COUNT) {
-		printk(KERN_ERR "[PS_ERR][CM36283 error] %s retry over %d\n",
-			__func__, I2C_RETRY_COUNT);
+		dev_err(&lpi->i2c_client->dev, "%s: Retry count exceeds %d.",
+				__func__, I2C_RETRY_COUNT);
 		return -EIO;
 	}
 
@@ -244,18 +231,12 @@
 
 	ret = I2C_RxData(slaveAddr, cmd, buffer, 2);
 	if (ret < 0) {
-		pr_err(
-			"[PS_ERR][CM3218 error]%s: I2C_RxData fail [0x%x, 0x%x]\n",
-			__func__, slaveAddr, cmd);
+		pr_err("%s: I2C RxData fail(%d).\n", __func__, cmd);
 		return ret;
 	}
 
 	*pdata = (buffer[1]<<8)|buffer[0];
-#if 0
-	/* Debug use */
-	printk(KERN_DEBUG "[CM3218] %s: I2C_RxData[0x%x, 0x%x] = 0x%x\n",
-		__func__, slaveAddr, cmd, *pdata);
-#endif
+
 	return ret;
 }
 
@@ -263,19 +244,14 @@
 {
 	char buffer[3];
 	int ret = 0;
-#if 0
-	/* Debug use */
-	printk(KERN_DEBUG
-	"[CM3218] %s: _cm36283_I2C_Write_Word[0x%x, 0x%x, 0x%x]\n",
-		__func__, SlaveAddress, cmd, data);
-#endif
+
 	buffer[0] = cmd;
 	buffer[1] = (uint8_t)(data&0xff);
 	buffer[2] = (uint8_t)((data&0xff00)>>8);	
 	
 	ret = I2C_TxData(SlaveAddress, buffer, 3);
 	if (ret < 0) {
-		pr_err("[PS_ERR][CM3218 error]%s: I2C_TxData fail\n", __func__);
+		pr_err("%s: I2C_TxData failed.\n", __func__);
 		return -EIO;
 	}
 
@@ -285,7 +261,7 @@
 static int get_ls_adc_value(uint16_t *als_step, bool resume)
 {
 	struct cm36283_info *lpi = lp_info;
-	uint32_t tmpResult;
+	uint32_t tmp;
 	int ret = 0;
 
 	if (als_step == NULL)
@@ -294,22 +270,20 @@
 	/* Read ALS data: */
 	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_DATA, als_step);
 	if (ret < 0) {
-		pr_err(
-			"[LS][CM3218 error]%s: _cm36283_I2C_Read_Word fail\n",
-			__func__);
+		dev_err(&lpi->i2c_client->dev, "%s: I2C read word failed.\n",
+				__func__);
 		return -EIO;
 	}
 
-  if (!lpi->ls_calibrate) {
-		tmpResult = (uint32_t)(*als_step) * lpi->als_gadc / lpi->als_kadc;
-		if (tmpResult > 0xFFFF)
+	if (!lpi->ls_calibrate) {
+		tmp = (uint32_t)(*als_step) * lpi->als_gadc / lpi->als_kadc;
+		if (tmp > 0xFFFF)
 			*als_step = 0xFFFF;
 		else
-		  *als_step = tmpResult;  			
+			*als_step = tmp;
 	}
 
-	D("[LS][CM3218] %s: raw adc = 0x%X, ls_calibrate = %d\n",
-		__func__, *als_step, lpi->ls_calibrate);
+	dev_dbg(&lpi->i2c_client->dev, "raw adc = 0x%x\n", *als_step);
 
 	return ret;
 }
@@ -335,18 +309,10 @@
 
 	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, PS_DATA, data);
 	
+	if (ret < 0)
+		return ret;
+
 	(*data) &= 0xFF;
-	
-	if (ret < 0) {
-		pr_err(
-			"[PS][CM36283 error]%s: _cm36283_I2C_Read_Word fail\n",
-			__func__);
-		return -EIO;
-	} else {
-		pr_err(
-			"[PS][CM36283 OK]%s: _cm36283_I2C_Read_Word OK 0x%x\n",
-			__func__, *data);
-	}
 
 	return ret;
 }
@@ -383,16 +349,16 @@
 			msleep(10);
 			wait_count++;
 			if (wait_count > 12) {
-				pr_err("[PS_ERR][CM36283 error]%s: interrupt GPIO low,"
-					" get_ps_adc_value\n", __func__);
+				dev_err(&lpi->i2c_client->dev, "%s: interrupt GPIO low\n",
+					       __func__);
 				return -EIO;
 			}
 		}
 
 		ret = get_ps_adc_value(&value[i]);
 		if (ret < 0) {
-			pr_err("[PS_ERR][CM36283 error]%s: get_ps_adc_value\n",
-				__func__);
+			dev_err(&lpi->i2c_client->dev,
+					"%s: error get ps value\n", __func__);
 			return -EIO;
 		}
 
@@ -402,10 +368,8 @@
 		wait_count = 0;
 	}
 
-	/*D("Sta_ps: Before sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
-		value[0], value[1], value[2]);*/
 	mid_val = mid_value(value, 3);
-	D("Sta_ps: After sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
+	dev_dbg(&lpi->i2c_client->dev, "Sta_ps: After sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
 		value[0], value[1], value[2]);
 	*ps_adc = (mid_val & 0xFF);
 
@@ -531,14 +495,16 @@
 
 static void psensor_initial_cmd(struct cm36283_info *lpi)
 {
-	/*must disable p-sensor interrupt befrore IST create*//*disable ALS func*/		
-  lpi->ps_conf1_val |= CM36283_PS_SD;
-  lpi->ps_conf1_val &= CM36283_PS_INT_MASK;  
-  _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);   
-  _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val);
-  _cm36283_I2C_Write_Word(lpi->slave_addr, PS_THD, (lpi->ps_close_thd_set <<8)| lpi->ps_away_thd_set);
+	/*must disable p-sensor interrupt befrore IST create*/
+	lpi->ps_conf1_val |= CM36283_PS_SD;
+	lpi->ps_conf1_val &= CM36283_PS_INT_MASK;
+	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);
+	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val);
+	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_THD,
+			(lpi->ps_close_thd_set << 8) | lpi->ps_away_thd_set);
 
-	D("[PS][CM36283] %s, finish\n", __func__);	
+	dev_dbg(&lpi->i2c_client->dev,
+			"%s:send psensor initial command finished\n", __func__);
 }
 
 static int psensor_enable(struct cm36283_info *lpi)
@@ -547,10 +513,10 @@
 	unsigned int delay;
 	
 	mutex_lock(&ps_enable_mutex);
-	D("[PS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "psensor enable!\n");
 
 	if (lpi->ps_enable) {
-		D("[PS][CM36283] %s: already enabled\n", __func__);
+		dev_err(&lpi->i2c_client->dev, "already enabled\n");
 		ret = 0;
 	} else {
 		ret = control_and_report(lpi, CONTROL_PS, 1, 0);
@@ -573,10 +539,10 @@
 		cancel_delayed_work_sync(&lpi->pdwork);
 
 	mutex_lock(&ps_disable_mutex);
-	D("[PS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "psensor disable!\n");
 
 	if (lpi->ps_enable == 0) {
-		D("[PS][CM36283] %s: already disabled\n", __func__);
+		dev_err(&lpi->i2c_client->dev, "already disabled\n");
 		ret = 0;
 	} else {
 		ret = control_and_report(lpi, CONTROL_PS, 0, 0);
@@ -590,7 +556,7 @@
 {
 	struct cm36283_info *lpi = lp_info;
 
-	D("[PS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "psensor open!");
 
 	if (lpi->psensor_opened)
 		return -EBUSY;
@@ -604,7 +570,7 @@
 {
 	struct cm36283_info *lpi = lp_info;
 
-	D("[PS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "psensor release!");
 
 	lpi->psensor_opened = 0;
 
@@ -618,7 +584,7 @@
 	int val;
 	struct cm36283_info *lpi = lp_info;
 
-	D("[PS][CM36283] %s cmd %d\n", __func__, _IOC_NR(cmd));
+	dev_dbg(&lpi->i2c_client->dev, "%s cmd %d\n", __func__, _IOC_NR(cmd));
 
 	switch (cmd) {
 	case CAPELLA_CM3602_IOCTL_ENABLE:
@@ -633,7 +599,7 @@
 		return put_user(lpi->ps_enable, (unsigned long __user *)arg);
 		break;
 	default:
-		pr_err("[PS][CM36283 error]%s: invalid cmd %d\n",
+		dev_err(&lpi->i2c_client->dev, "%s: invalid cmd %d\n",
 			__func__, _IOC_NR(cmd));
 		return -EINVAL;
 	}
@@ -655,18 +621,19 @@
 void lightsensor_set_kvalue(struct cm36283_info *lpi)
 {
 	if (!lpi) {
-		pr_err("[LS][CM36283 error]%s: ls_info is empty\n", __func__);
+		pr_err("%s: ls_info is empty\n", __func__);
 		return;
 	}
 
-	D("[LS][CM36283] %s: ALS calibrated als_kadc=0x%x\n",
+	dev_dbg(&lpi->i2c_client->dev, "%s: ALS calibrated als_kadc=0x%x\n",
 			__func__, als_kadc);
 
 	if (als_kadc >> 16 == ALS_CALIBRATED)
 		lpi->als_kadc = als_kadc & 0xFFFF;
 	else {
 		lpi->als_kadc = 0;
-		D("[LS][CM36283] %s: no ALS calibrated\n", __func__);
+		dev_dbg(&lpi->i2c_client->dev, "%s: no ALS calibrated\n",
+				__func__);
 	}
 
 	if (lpi->als_kadc && lpi->golden_adc > 0) {
@@ -677,25 +644,26 @@
 		lpi->als_kadc = 1;
 		lpi->als_gadc = 1;
 	}
-	D("[LS][CM36283] %s: als_kadc=0x%x, als_gadc=0x%x\n",
+	dev_dbg(&lpi->i2c_client->dev, "%s: als_kadc=0x%x, als_gadc=0x%x\n",
 		__func__, lpi->als_kadc, lpi->als_gadc);
 }
 
 
 static int lightsensor_update_table(struct cm36283_info *lpi)
 {
-	uint32_t tmpData[10];
+	uint32_t tmp_data[10];
 	int i;
 	for (i = 0; i < 10; i++) {
-		tmpData[i] = (uint32_t)(*(lpi->adc_table + i))
-				* lpi->als_kadc / lpi->als_gadc ;
-		if( tmpData[i] <= 0xFFFF ){
-      lpi->cali_table[i] = (uint16_t) tmpData[i];		
-    } else {
-      lpi->cali_table[i] = 0xFFFF;    
-    }         
-		D("[LS][CM36283] %s: Calibrated adc_table: data[%d], %x\n",
-			__func__, i, lpi->cali_table[i]);
+		tmp_data[i] = (uint32_t)(*(lpi->adc_table + i))
+			* lpi->als_kadc / lpi->als_gadc;
+
+		if (tmp_data[i] <= 0xFFFF)
+			lpi->cali_table[i] = (uint16_t) tmp_data[i];
+		else
+			lpi->cali_table[i] = 0xFFFF;
+
+		dev_dbg(&lpi->i2c_client->dev, "%s: Calibrated adc_table: data[%d], %x\n",
+				__func__, i, lpi->cali_table[i]);
 	}
 
 	return 0;
@@ -708,10 +676,10 @@
 	unsigned int delay;
 	
 	mutex_lock(&als_enable_mutex);
-	D("[LS][CM36283] %s\n", __func__);
 
 	if (lpi->als_enable) {
-		D("[LS][CM36283] %s: already enabled\n", __func__);
+		dev_err(&lpi->i2c_client->dev, "%s: already enabled\n",
+			       __func__);
 		ret = 0;
 	} else {
 		ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
@@ -731,13 +699,13 @@
 {
 	int ret = -EIO;
 	mutex_lock(&als_disable_mutex);
-	D("[LS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "disable lightsensor\n");
 
 	if (lpi->polling)
 		cancel_delayed_work_sync(&lpi->ldwork);
 
 	if ( lpi->als_enable == 0 ) {
-		D("[LS][CM36283] %s: already disabled\n", __func__);
+		dev_err(&lpi->i2c_client->dev, "already disabled\n");
 		ret = 0;
 	} else {
 		ret = control_and_report(lpi, CONTROL_ALS, 0, 0);
@@ -752,9 +720,10 @@
 	struct cm36283_info *lpi = lp_info;
 	int rc = 0;
 
-	D("[LS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "%s\n", __func__);
 	if (lpi->lightsensor_opened) {
-		pr_err("[LS][CM36283 error]%s: already opened\n", __func__);
+		dev_err(&lpi->i2c_client->dev, "%s: already opened\n",
+				__func__);
 		rc = -EBUSY;
 	}
 	lpi->lightsensor_opened = 1;
@@ -765,7 +734,7 @@
 {
 	struct cm36283_info *lpi = lp_info;
 
-	D("[LS][CM36283] %s\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "%s\n", __func__);
 	lpi->lightsensor_opened = 0;
 	return 0;
 }
@@ -776,22 +745,16 @@
 	int rc, val;
 	struct cm36283_info *lpi = lp_info;
 
-	/*D("[CM36283] %s cmd %d\n", __func__, _IOC_NR(cmd));*/
-
 	switch (cmd) {
 	case LIGHTSENSOR_IOCTL_ENABLE:
 		if (get_user(val, (unsigned long __user *)arg)) {
 			rc = -EFAULT;
 			break;
 		}
-		D("[LS][CM36283] %s LIGHTSENSOR_IOCTL_ENABLE, value = %d\n",
-			__func__, val);
 		rc = val ? lightsensor_enable(lpi) : lightsensor_disable(lpi);
 		break;
 	case LIGHTSENSOR_IOCTL_GET_ENABLED:
 		val = lpi->als_enable;
-		D("[LS][CM36283] %s LIGHTSENSOR_IOCTL_GET_ENABLED, enabled %d\n",
-			__func__, val);
 		rc = put_user(val, (unsigned long __user *)arg);
 		break;
 	default:
@@ -850,29 +813,28 @@
 		&& ps_en != 10 && ps_en != 13 && ps_en != 16)
 		return -EINVAL;
 
-	if (ps_en) {
-		D("[PS][CM36283] %s: ps_en=%d\n",
+	dev_dbg(&lpi->i2c_client->dev, "%s: ps_en=%d\n",
 			__func__, ps_en);
-		psensor_enable(lpi);
-	} else
-		psensor_disable(lpi);
 
-	D("[PS][CM36283] %s\n", __func__);
+	if (ps_en)
+		psensor_enable(lpi);
+	else
+		psensor_disable(lpi);
 
 	return count;
 }
 
 static DEVICE_ATTR(ps_adc, 0664, ps_adc_show, ps_enable_store);
 
-unsigned PS_cmd_test_value;
 static ssize_t ps_parameters_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
 	int ret;
 	struct cm36283_info *lpi = lp_info;
 
-	ret = sprintf(buf, "PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x, PS_cmd_cmd:value = 0x%x\n",
-		lpi->ps_close_thd_set, lpi->ps_away_thd_set, PS_cmd_test_value);
+	ret = snprintf(buf, PAGE_SIZE,
+			"PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x\n",
+			lpi->ps_close_thd_set, lpi->ps_away_thd_set);
 
 	return ret;
 }
@@ -885,19 +847,23 @@
 	struct cm36283_info *lpi = lp_info;
 	char *token[10];
 	int i;
+	unsigned long tmp;
 
-	printk(KERN_INFO "[PS][CM36283] %s\n", buf);
 	for (i = 0; i < 3; i++)
 		token[i] = strsep((char **)&buf, " ");
 
-	lpi->ps_close_thd_set = simple_strtoul(token[0], NULL, 16);
-	lpi->ps_away_thd_set = simple_strtoul(token[1], NULL, 16);	
-	PS_cmd_test_value = simple_strtoul(token[2], NULL, 16);
-	printk(KERN_INFO
-		"[PS][CM36283]Set PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x, PS_cmd_cmd:value = 0x%x\n",
-		lpi->ps_close_thd_set, lpi->ps_away_thd_set, PS_cmd_test_value);
+	if (kstrtoul(token[0], 16, &tmp))
+		return -EINVAL;
+	lpi->ps_close_thd_set = tmp;
 
-	D("[PS][CM36283] %s\n", __func__);
+	if (kstrtoul(token[1], 16, &tmp))
+		return -EINVAL;
+	lpi->ps_away_thd_set = tmp;
+
+	dev_dbg(&lpi->i2c_client->dev, "ps_close_thd_set:0x%x\n",
+			lpi->ps_close_thd_set);
+	dev_dbg(&lpi->i2c_client->dev, "ps_away_thd_set:0x%x\n",
+			lpi->ps_away_thd_set);
 
 	return count;
 }
@@ -920,14 +886,14 @@
 	struct cm36283_info *lpi = lp_info;
 
 	sscanf(buf, "0x%x 0x%x", &code1, &code2);
+	dev_dbg(&lpi->i2c_client->dev, "PS_CONF1:0x%x PS_CONF3:0x%x\n",
+			code1, code2);
 
-	D("[PS]%s: store value PS conf1 reg = 0x%x PS conf3 reg = 0x%x\n", __func__, code1, code2);
+	lpi->ps_conf1_val = code1;
+	lpi->ps_conf3_val = code2;
 
-  lpi->ps_conf1_val = code1;
-  lpi->ps_conf3_val = code2;
-
-	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val );  
-	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val );
+	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val);
+	_cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);
 
 	return count;
 }
@@ -950,12 +916,13 @@
 
 	sscanf(buf, "0x%x", &code);
 
-	D("[PS]%s: store value = 0x%x\n", __func__, code);
-
 	lpi->ps_away_thd_set = code &0xFF;
-	lpi->ps_close_thd_set = (code &0xFF00)>>8;	
+	lpi->ps_close_thd_set = (code & 0xFF00)>>8;
 
-	D("[PS]%s: ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n", __func__, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+	dev_dbg(&lpi->i2c_client->dev, "ps_away_thd_set:0x%x\n",
+			lpi->ps_away_thd_set);
+	dev_dbg(&lpi->i2c_client->dev, "ps_close_thd_set:0x%x\n",
+			lpi->ps_close_thd_set);
 
 	return count;
 }
@@ -977,12 +944,9 @@
 				const char *buf, size_t count)
 {
 	int code;
-//	struct cm36283_info *lpi = lp_info;
 
 	sscanf(buf, "0x%x", &code);
 
-	D("[PS]%s: store value = 0x%x\n", __func__, code);
-
 	return count;
 }
 static DEVICE_ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store);
@@ -993,8 +957,6 @@
 	int ret;
 	struct cm36283_info *lpi = lp_info;
 
-	D("[LS][CM36283] %s: ADC = 0x%04X, Level = %d \n",
-		__func__, lpi->current_adc, lpi->current_level);
 	ret = sprintf(buf, "ADC[0x%04X] => level %d\n",
 		lpi->current_adc, lpi->current_level);
 
@@ -1038,12 +1000,14 @@
 		ret = lightsensor_disable(lpi);
 	}
 
-	D("[LS][CM36283] %s: lpi->als_enable = %d, lpi->ls_calibrate = %d, ls_auto=%d\n",
-		__func__, lpi->als_enable, lpi->ls_calibrate, ls_auto);
+	dev_dbg(&lpi->i2c_client->dev, "als_enable:0x%x\n",
+			lpi->als_enable);
+	dev_dbg(&lpi->i2c_client->dev, "ls_calibrate:0x%x\n",
+			lpi->ls_calibrate);
+	dev_dbg(&lpi->i2c_client->dev, "ls_auto:0x%x\n", ls_auto);
 
 	if (ret < 0)
-		pr_err(
-		"[LS][CM36283 error]%s: set auto light sensor fail\n",
+		dev_err(&lpi->i2c_client->dev, "%s: set auto light sensor fail\n",
 		__func__);
 
 	return count;
@@ -1074,17 +1038,18 @@
 	sscanf(buf, "%d", &kadc_temp);
 
 	mutex_lock(&als_get_adc_mutex);
-  if(kadc_temp != 0) {
+	if (kadc_temp != 0) {
 		lpi->als_kadc = kadc_temp;
-		if(  lpi->als_gadc != 0){
-  		if (lightsensor_update_table(lpi) < 0)
-				printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n", __func__);
-  	} else {
-			printk(KERN_INFO "[LS]%s: als_gadc =0x%x wait to be set\n",
-					__func__, lpi->als_gadc);
-  	}		
+		if (lpi->als_gadc != 0) {
+			if (lightsensor_update_table(lpi) < 0)
+				dev_err(&lpi->i2c_client->dev, "%s: update ls table fail\n",
+						__func__);
+			else
+				dev_dbg(&lpi->i2c_client->dev, "%s: als_gadc =0x%x wait to be set\n",
+						__func__, lpi->als_gadc);
+		}
 	} else {
-		printk(KERN_INFO "[LS]%s: als_kadc can't be set to zero\n",
+		dev_err(&lpi->i2c_client->dev, "%s: als_kadc can't be set to zero\n",
 				__func__);
 	}
 				
@@ -1115,18 +1080,18 @@
 	sscanf(buf, "%d", &gadc_temp);
 	
 	mutex_lock(&als_get_adc_mutex);
-  if(gadc_temp != 0) {
+	if (gadc_temp != 0) {
 		lpi->als_gadc = gadc_temp;
-		if(  lpi->als_kadc != 0){
-  		if (lightsensor_update_table(lpi) < 0)
-				printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n", __func__);
-  	} else {
-			printk(KERN_INFO "[LS]%s: als_kadc =0x%x wait to be set\n",
-					__func__, lpi->als_kadc);
-  	}		
+		if (lpi->als_kadc != 0) {
+			if (lightsensor_update_table(lpi) < 0)
+				dev_err(&lpi->i2c_client->dev, "%s: update ls table fail\n",
+						__func__);
+		} else {
+			dev_dbg(&lpi->i2c_client->dev, "als_kadc =0x%x wait to be set\n",
+					lpi->als_kadc);
+		}
 	} else {
-		printk(KERN_INFO "[LS]%s: als_gadc can't be set to zero\n",
-				__func__);
+		dev_err(&lpi->i2c_client->dev, "als_gadc can't be set to zero\n");
 	}
 	mutex_unlock(&als_get_adc_mutex);
 	return count;
@@ -1161,29 +1126,24 @@
 	uint16_t tempdata[10];
 	int i;
 
-	printk(KERN_INFO "[LS][CM36283]%s\n", buf);
 	for (i = 0; i < 10; i++) {
 		token[i] = strsep((char **)&buf, " ");
 		tempdata[i] = simple_strtoul(token[i], NULL, 16);
 		if (tempdata[i] < 1 || tempdata[i] > 0xffff) {
-			printk(KERN_ERR
-			"[LS][CM36283 error] adc_table[%d] =  0x%x Err\n",
+			dev_err(&lpi->i2c_client->dev,
+			"adc_table[%d] =  0x%x error\n",
 			i, tempdata[i]);
 			return count;
 		}
 	}
 	mutex_lock(&als_get_adc_mutex);
-	for (i = 0; i < 10; i++) {
+	for (i = 0; i < 10; i++)
 		lpi->adc_table[i] = tempdata[i];
-		printk(KERN_INFO
-		"[LS][CM36283]Set lpi->adc_table[%d] =  0x%x\n",
-		i, *(lp_info->adc_table + i));
-	}
+
 	if (lightsensor_update_table(lpi) < 0)
-		printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n",
+		dev_err(&lpi->i2c_client->dev, "%s: update ls table fail\n",
 		__func__);
 	mutex_unlock(&als_get_adc_mutex);
-	D("[LS][CM36283] %s\n", __func__);
 
 	return count;
 }
@@ -1206,8 +1166,9 @@
 	sscanf(buf, "0x%x", &value);
 
 	lpi->ls_cmd = value;
-	printk(KERN_INFO "[LS]set ALS_CONF = %x\n", lpi->ls_cmd);
-	
+
+	dev_dbg(&lpi->i2c_client->dev, "ALS_CONF:0x%x\n", lpi->ls_cmd);
+
 	_cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
 	return count;
 }
@@ -1285,7 +1246,6 @@
 	fLevel=value;
 	input_report_abs(lpi->ls_input_dev, ABS_MISC, fLevel);
 	input_sync(lpi->ls_input_dev);
-	printk(KERN_INFO "[LS]set fLevel = %d\n", fLevel);
 
 	msleep(1000);
 	fLevel=-1;
@@ -1381,7 +1341,8 @@
 	uint16_t idReg;
 
 	val = gpio_get_value(lpi->intr_pin);
-	D("[PS][CM36283] %s, INTERRUPT GPIO val = %d\n", __func__, val);
+	dev_dbg(&lpi->i2c_client->dev, "%s, INTERRUPT GPIO val = %d\n",
+		       __func__, val);
 
 	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ID_REG, &idReg);
 
@@ -1545,15 +1506,10 @@
 	struct cm36283_info *lpi;
 	struct cm36283_platform_data *pdata;
 
-	D("[PS][CM36283] %s\n", __func__);
-
-
 	lpi = kzalloc(sizeof(struct cm36283_info), GFP_KERNEL);
 	if (!lpi)
 		return -ENOMEM;
 
-	/*D("[CM36283] %s: client->irq = %d\n", __func__, client->irq);*/
-
 	lpi->i2c_client = client;
 
 	if (client->dev.of_node) {
@@ -1605,7 +1561,7 @@
 	
 	lpi->record_clear_int_fail=0;
 	
-	D("[PS][CM36283] %s: ls_cmd 0x%x\n",
+	dev_dbg(&lpi->i2c_client->dev, "[PS][CM36283] %s: ls_cmd 0x%x\n",
 		__func__, lpi->ls_cmd);
 	
 	if (pdata->ls_cmd == 0) {
@@ -1777,7 +1733,7 @@
 	mutex_init(&wq_lock);
 	INIT_DELAYED_WORK(&lpi->ldwork, lsensor_delay_work_handler);
 	INIT_DELAYED_WORK(&lpi->pdwork, psensor_delay_work_handler);
-	D("[PS][CM36283] %s: Probe success!\n", __func__);
+	dev_dbg(&lpi->i2c_client->dev, "%s: Probe success!\n", __func__);
 
 	return ret;
 
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index f49ff14..a325d54 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -304,6 +304,28 @@
 	return 0;
 }
 
+static int mma8x5x_device_start(struct i2c_client *client)
+{
+	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+
+	if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+		goto err_out;
+	if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
+			pdata->mode))
+		goto err_out;
+
+	/* The BT(boot time) for mma8x5x is 1.55ms according to
+	  *Freescale mma8450Q document. Document Number:MMA8450Q
+	  *Rev: 9.1, 04/2012
+	  */
+	usleep_range(1600, 2000);
+	return 0;
+
+err_out:
+	dev_err(&client->dev, "%s:start device failed", __func__);
+	return -EIO;
+}
+
 static int mma8x5x_read_data(struct i2c_client *client,
 		struct mma8x5x_data_axis *data)
 {
@@ -381,32 +403,73 @@
 	int ret;
 	unsigned long enable;
 	u8 val = 0;
+
 	ret = kstrtoul(buf, 10, &enable);
 	if (ret)
 		return ret;
 	mutex_lock(&pdata->data_lock);
 	enable = (enable > 0) ? 1 : 0;
-	if (enable && pdata->active == MMA_STANDBY) {
-		val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
-		ret = i2c_smbus_write_byte_data(client,
-				MMA8X5X_CTRL_REG1, val|0x01);
-		if (!ret) {
+	if (enable) {
+		if (pdata->active & MMA_SHUTTEDDOWN) {
+			ret = mma8x5x_config_regulator(client, 1);
+			if (ret)
+				goto err_failed;
+
+			ret = mma8x5x_device_start(client);
+			if (ret)
+				goto err_failed;
+
+			pdata->active &= ~MMA_SHUTTEDDOWN;
+		}
+		if (pdata->active == MMA_STANDBY) {
+			val = i2c_smbus_read_byte_data(client,
+					MMA8X5X_CTRL_REG1);
+			if (val < 0) {
+				dev_err(dev, "read device state failed!");
+				ret = val;
+				goto err_failed;
+			}
+
+			ret = i2c_smbus_write_byte_data(client,
+					MMA8X5X_CTRL_REG1, val | 0x01);
+			if (ret) {
+				dev_err(dev, "change device state failed!");
+				goto err_failed;
+			}
 			pdata->active = MMA_ACTIVED;
-			dev_dbg(dev,
-				"%s:mma enable setting active.\n", __func__);
+			dev_dbg(dev, "%s:mma enable setting active.\n",
+					__func__);
 		}
-	} else if (enable == 0  && pdata->active == MMA_ACTIVED) {
-		val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
-		ret = i2c_smbus_write_byte_data(client,
-			MMA8X5X_CTRL_REG1, val & 0xFE);
-		if (!ret) {
+	} else if (enable == 0) {
+		if (pdata->active == MMA_ACTIVED) {
+			val = i2c_smbus_read_byte_data(client,
+					MMA8X5X_CTRL_REG1);
+			if (val < 0) {
+				dev_err(dev, "read device state failed!");
+				ret = val;
+				goto err_failed;
+			}
+
+			ret = i2c_smbus_write_byte_data(client,
+				MMA8X5X_CTRL_REG1, val & 0xFE);
+			if (ret) {
+				dev_err(dev, "change device state failed!");
+				goto err_failed;
+			}
+
 			pdata->active = MMA_STANDBY;
-			dev_dbg(dev,
-				"%s:mma enable setting inactive.\n", __func__);
+			dev_dbg(dev, "%s:mma enable setting inactive.\n",
+					__func__);
 		}
+		if (!mma8x5x_config_regulator(client, 0))
+			pdata->active |= MMA_SHUTTEDDOWN;
 	}
 	mutex_unlock(&pdata->data_lock);
 	return count;
+
+err_failed:
+	mutex_unlock(&pdata->data_lock);
+	return ret;
 }
 static ssize_t mma8x5x_position_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
@@ -617,6 +680,8 @@
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
 	if (pdata->active == MMA_ACTIVED)
 		mma8x5x_device_stop(client);
+	if (pdata->active & MMA_SHUTTEDDOWN)
+		return 0;
 	if (!mma8x5x_config_regulator(client, 0))
 		/* The highest bit sotres the power state */
 		pdata->active |= MMA_SHUTTEDDOWN;
@@ -628,22 +693,16 @@
 	int val = 0;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+
+	/* No need to power on while device is shutdowned from standby state */
+	if (pdata->active == (MMA_SHUTTEDDOWN | MMA_STANDBY))
+		return 0;
 	if (pdata->active & MMA_SHUTTEDDOWN) {
 		if (mma8x5x_config_regulator(client, 1))
 			goto out;
 
-		if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+		if (mma8x5x_device_start(client))
 			goto out;
-
-		if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
-				pdata->mode))
-			goto out;
-
-		/* The BT(boot time) for mma8x5x is 1.55ms according to
-		Freescale mma8450Q document. Document Number:MMA8450Q
-		Rev: 9.1, 04/2012
-		*/
-		usleep_range(1600, 2000);
 		pdata->active &= ~MMA_SHUTTEDDOWN;
 	}
 	if (pdata->active == MMA_ACTIVED) {
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 06ca31c..4dbe5c1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -399,7 +399,6 @@
 #if defined(CONFIG_SECURE_TOUCH)
 	atomic_t st_enabled;
 	atomic_t st_pending_irqs;
-	struct completion st_completion;
 	struct completion st_powerdown;
 #endif
 };
@@ -1002,11 +1001,16 @@
 }
 
 #if defined(CONFIG_SECURE_TOUCH)
+static void mxt_secure_touch_notify(struct mxt_data *data)
+{
+	sysfs_notify(&data->client->dev.kobj, NULL, "secure_touch");
+}
+
 static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
 {
 	if (atomic_read(&data->st_enabled)) {
 		if (atomic_cmpxchg(&data->st_pending_irqs, 0, 1) == 0)
-			complete(&data->st_completion);
+			mxt_secure_touch_notify(data);
 		return IRQ_HANDLED;
 	}
 	return IRQ_NONE;
@@ -1998,7 +2002,7 @@
 
 		pm_runtime_put(data->client->adapter->dev.parent);
 		atomic_set(&data->st_enabled, 0);
-		complete(&data->st_completion);
+		mxt_secure_touch_notify(data);
 		mxt_interrupt(data->client->irq, data);
 		complete(&data->st_powerdown);
 		break;
@@ -2013,7 +2017,6 @@
 			err = -EIO;
 			break;
 		}
-		INIT_COMPLETION(data->st_completion);
 		INIT_COMPLETION(data->st_powerdown);
 		atomic_set(&data->st_enabled, 1);
 		synchronize_irq(data->client->irq);
@@ -2032,20 +2035,18 @@
 				    struct device_attribute *attr, char *buf)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
-	int err;
+	int val = 0;
 
 	if (atomic_read(&data->st_enabled) == 0)
 		return -EBADF;
 
-	err = wait_for_completion_interruptible(&data->st_completion);
-
-	if (err)
-		return err;
-
-	if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) != 1)
+	if (atomic_cmpxchg(&data->st_pending_irqs, -1, 0) == -1)
 		return -EINVAL;
 
-	return scnprintf(buf, PAGE_SIZE, "%u", 1);
+	if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) == 1)
+		val = 1;
+
+	return scnprintf(buf, PAGE_SIZE, "%u", val);
 }
 
 static DEVICE_ATTR(secure_touch_enable, 0666, mxt_secure_touch_enable_show,
@@ -2074,15 +2075,17 @@
 
 
 #if defined(CONFIG_SECURE_TOUCH)
-static void mxt_secure_touch_stop(struct mxt_data *data)
+static void mxt_secure_touch_stop(struct mxt_data *data, int blocking)
 {
 	if (atomic_read(&data->st_enabled)) {
-		complete(&data->st_completion);
-		wait_for_completion_interruptible(&data->st_powerdown);
+		atomic_set(&data->st_pending_irqs, -1);
+		mxt_secure_touch_notify(data);
+		if (blocking)
+			wait_for_completion_interruptible(&data->st_powerdown);
 	}
 }
 #else
-static void mxt_secure_touch_stop(struct mxt_data *data)
+static void mxt_secure_touch_stop(struct mxt_data *data, int blocking)
 {
 }
 #endif
@@ -2090,7 +2093,7 @@
 static int mxt_start(struct mxt_data *data)
 {
 	int error;
-	mxt_secure_touch_stop(data);
+	mxt_secure_touch_stop(data, 1);
 
 	/* restore the old power state values and reenable touch */
 	error = __mxt_write_reg(data->client, data->t7_start_addr,
@@ -2108,7 +2111,7 @@
 {
 	int error;
 	u8 t7_data[T7_DATA_SIZE] = {0};
-	mxt_secure_touch_stop(data);
+	mxt_secure_touch_stop(data, 1);
 
 	error = __mxt_write_reg(data->client, data->t7_start_addr,
 				T7_DATA_SIZE, t7_data);
@@ -2523,7 +2526,7 @@
 
 	/* calibrate */
 	if (data->pdata->need_calibration) {
-		mxt_secure_touch_stop(data);
+		mxt_secure_touch_stop(data, 1);
 		error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
 					MXT_COMMAND_CALIBRATE, 1);
 		if (error < 0)
@@ -2836,13 +2839,14 @@
 	struct mxt_data *mxt_dev_data =
 		container_of(self, struct mxt_data, fb_notif);
 
-	if (evdata && evdata->data && event == FB_EVENT_BLANK && mxt_dev_data &&
-			mxt_dev_data->client) {
-		blank = evdata->data;
-		if (*blank == FB_BLANK_UNBLANK)
-			mxt_resume(&mxt_dev_data->client->dev);
-		else if (*blank == FB_BLANK_POWERDOWN)
-			mxt_suspend(&mxt_dev_data->client->dev);
+	if (evdata && evdata->data && mxt_dev_data && mxt_dev_data->client) {
+		if (event == FB_EVENT_BLANK) {
+			blank = evdata->data;
+			if (*blank == FB_BLANK_UNBLANK)
+				mxt_resume(&mxt_dev_data->client->dev);
+			else if (*blank == FB_BLANK_POWERDOWN)
+				mxt_suspend(&mxt_dev_data->client->dev);
+		}
 	}
 
 	return 0;
@@ -2867,7 +2871,6 @@
 #if defined(CONFIG_SECURE_TOUCH)
 static void __devinit mxt_secure_touch_init(struct mxt_data *data)
 {
-	init_completion(&data->st_completion);
 	init_completion(&data->st_powerdown);
 }
 #else
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 2f9ea10..aa50d44 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -336,7 +336,6 @@
 			input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
 		} else {
 			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
-			input_report_abs(ip_dev, ABS_MT_PRESSURE, 0);
 		}
 	}
 
@@ -1247,6 +1246,9 @@
 	pdata->fw_vkey_support = of_property_read_bool(np,
 						"focaltech,fw-vkey-support");
 
+	pdata->ignore_id_check = of_property_read_bool(np,
+						"focaltech,ignore-id-check");
+
 	rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
 	if (!rc)
 		pdata->family_id = temp_val;
@@ -1447,7 +1449,7 @@
 
 	dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);
 
-	if (pdata->family_id != reg_value) {
+	if ((pdata->family_id != reg_value) && (!pdata->ignore_id_check)) {
 		dev_err(&client->dev, "%s:Unsupported controller\n", __func__);
 		goto free_reset_gpio;
 	}
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index bdac3fd..aa8159f 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -22,6 +22,7 @@
  */
 
 #include "gt9xx.h"
+#include <linux/mutex.h>
 
 #define DATA_LENGTH_UINT    512
 #define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8 *))
@@ -53,6 +54,8 @@
 
 static struct proc_dir_entry *goodix_proc_entry;
 
+static struct mutex lock;
+
 static s32 goodix_tool_write(struct file *filp, const char __user *buff,
 						unsigned long len, void *data);
 static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
@@ -188,7 +191,7 @@
 
 s32 init_wr_node(struct i2c_client *client)
 {
-	s32 i;
+	u8 i;
 
 	gt_client = client;
 	memset(&cmd_head, 0, sizeof(cmd_head));
@@ -202,8 +205,8 @@
 		i--;
 	}
 	if (i) {
-		DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
-		GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+		DATA_LENGTH = i * DATA_LENGTH_UINT;
+		dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
 	} else {
 		GTP_ERROR("Apply for memory failed.");
 		return FAIL;
@@ -214,8 +217,9 @@
 
 	register_i2c_func();
 
+	mutex_init(&lock);
 	tool_set_proc_name(procname);
-	goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+	goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
 	if (goodix_proc_entry == NULL) {
 		GTP_ERROR("Couldn't create proc entry!");
 		return FAIL;
@@ -334,9 +338,13 @@
 	GTP_DEBUG_FUNC();
 	GTP_DEBUG_ARRAY((u8 *)buff, len);
 
+	mutex_lock(&lock);
 	ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
-	if (ret)
+	if (ret) {
 		GTP_ERROR("copy_from_user failed.");
+		ret = -EACCES;
+		goto exit;
+	}
 
 	GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);
 	GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
@@ -354,6 +362,19 @@
 	GTP_DEBUG("len:%d.", (s32)len);
 	GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
 
+	if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
+		pr_err("data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
+		ret = -EINVAL;
+		goto exit;
+	}
+	if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
+		pr_err(" addr len %d > data buff %d, rejected!\n",
+			cmd_head.addr_len, GTP_ADDR_LENGTH);
+		ret = -EINVAL;
+		goto exit;
+	}
+
 	if (cmd_head.wr == 1) {
 		/*  copy_from_user(&cmd_head.data[cmd_head.addr_len],
 				&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
@@ -373,7 +394,8 @@
 		if (cmd_head.flag == 1) {
 			if (FAIL == comfirm()) {
 				GTP_ERROR("[WRITE]Comfirm fail!");
-				return FAIL;
+				ret = -EINVAL;
+				goto exit;
 			}
 		} else if (cmd_head.flag == 2) {
 			/* Need interrupt! */
@@ -382,7 +404,8 @@
 		&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
 		cmd_head.data_len + cmd_head.addr_len) <= 0) {
 			GTP_ERROR("[WRITE]Write data failed!");
-			return FAIL;
+			ret = -EIO;
+			goto exit;
 		}
 
 		GTP_DEBUG_ARRAY(
@@ -391,7 +414,8 @@
 		if (cmd_head.delay)
 			msleep(cmd_head.delay);
 
-		return cmd_head.data_len + CMD_HEAD_LENGTH;
+		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 3) {  /* Write ic type */
 
 		ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
@@ -399,30 +423,40 @@
 		if (ret)
 			GTP_ERROR("copy_from_user failed.");
 
+		if (cmd_head.data_len > sizeof(IC_TYPE)) {
+			pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len, sizeof(IC_TYPE));
+			ret = -EINVAL;
+			goto exit;
+		}
 		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
 
 		register_i2c_func();
 
-		return cmd_head.data_len + CMD_HEAD_LENGTH;
-	} else if (cmd_head.wr == 3) {
+		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+		goto exit;
+	} else if (cmd_head.wr == 5) {
 
 		/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
 
-		return cmd_head.data_len + CMD_HEAD_LENGTH;
+		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 7) { /* disable irq! */
 		gtp_irq_disable(i2c_get_clientdata(gt_client));
 
 		#if GTP_ESD_PROTECT
 		gtp_esd_switch(gt_client, SWITCH_OFF);
 		#endif
-		return CMD_HEAD_LENGTH;
+		ret = CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 9) { /* enable irq! */
 		gtp_irq_enable(i2c_get_clientdata(gt_client));
 
 		#if GTP_ESD_PROTECT
 		gtp_esd_switch(gt_client, SWITCH_ON);
 		#endif
-		return CMD_HEAD_LENGTH;
+		ret = CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 17) {
 		struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
 		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
@@ -436,27 +470,41 @@
 			ts->gtp_rawdiff_mode = false;
 			GTP_DEBUG("gtp leave rawdiff.");
 		}
-		return CMD_HEAD_LENGTH;
+		ret = CMD_HEAD_LENGTH;
+		goto exit;
 	}
 #ifdef UPDATE_FUNCTIONS
 	else if (cmd_head.wr == 11) { /* Enter update mode! */
-		if (FAIL == gup_enter_update_mode(gt_client))
-			return FAIL;
+		if (FAIL == gup_enter_update_mode(gt_client)) {
+			ret = -EBUSY;
+			goto exit;
+		}
 	} else if (cmd_head.wr == 13) { /* Leave update mode! */
 		gup_leave_update_mode();
 	} else if (cmd_head.wr == 15) { /* Update firmware! */
 		show_len = 0;
 		total_len = 0;
+		if (cmd_head.data_len + 1 > DATA_LENGTH) {
+			pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len + 1, DATA_LENGTH);
+			ret = -EINVAL;
+			goto exit;
+		}
 		memset(cmd_head.data, 0, cmd_head.data_len + 1);
 		memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
 					cmd_head.data_len);
 
-		if (FAIL == gup_update_proc((void *)cmd_head.data))
-			return FAIL;
+		if (FAIL == gup_update_proc((void *)cmd_head.data)) {
+			ret = -EBUSY;
+			goto exit;
+		}
 	}
 #endif
+	ret = CMD_HEAD_LENGTH;
 
-	return CMD_HEAD_LENGTH;
+exit:
+	mutex_unlock(&lock);
+	return ret;
 }
 
 /*******************************************************
@@ -470,10 +518,14 @@
 static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
 							int *eof, void *data)
 {
+	s32 ret;
 	GTP_DEBUG_FUNC();
 
+	mutex_lock(&lock);
 	if (cmd_head.wr % 2) {
-		return FAIL;
+		pr_err("<< [READ]command head wrong\n");
+		ret = -EINVAL;
+		goto exit;
 	} else if (!cmd_head.wr) {
 		u16 len = 0;
 		s16 data_len = 0;
@@ -482,7 +534,8 @@
 		if (cmd_head.flag == 1) {
 			if (FAIL == comfirm()) {
 				GTP_ERROR("[READ]Comfirm fail!");
-				return FAIL;
+				ret = -EINVAL;
+				goto exit;
 			}
 		} else if (cmd_head.flag == 2) {
 			/* Need interrupt! */
@@ -505,11 +558,12 @@
 			else
 				len = data_len;
 
-			data_len -= DATA_LENGTH;
+			data_len -= len;
 
 			if (tool_i2c_read(cmd_head.data, len) <= 0) {
 				GTP_ERROR("[READ]Read data failed!");
-				return FAIL;
+				ret = -EINVAL;
+				goto exit;
 			}
 			memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
 									len);
@@ -525,15 +579,14 @@
 
 		GTP_DEBUG("Return ic type:%s len:%d.", page,
 						(s32)cmd_head.data_len);
-		return cmd_head.data_len;
+		ret = cmd_head.data_len;
+		goto exit;
 		/* return sizeof(IC_TYPE_NAME); */
 	} else if (cmd_head.wr == 4) {
 		page[0] = show_len >> 8;
 		page[1] = show_len & 0xff;
 		page[2] = total_len >> 8;
 		page[3] = total_len & 0xff;
-
-		return cmd_head.data_len;
 	} else if (6 == cmd_head.wr) {
 		/* Read error code! */
 	} else if (8 == cmd_head.wr) { /*Read driver version */
@@ -544,6 +597,9 @@
 		memcpy(page, GTP_DRIVER_VERSION, tmp_len);
 		page[tmp_len] = 0;
 	}
+	ret = cmd_head.data_len;
 
-	return cmd_head.data_len;
+exit:
+	mutex_unlock(&lock);
+	return ret;
 }
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 33ef141..8b08ac9 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -72,7 +72,8 @@
 #define RESET_DELAY_T3_US	200	/* T3: > 100us */
 #define RESET_DELAY_T4		20	/* T4: > 5ms */
 
-#define	PHY_BUF_SIZE		32
+#define PHY_BUF_SIZE		32
+#define PROP_NAME_SIZE		24
 
 #define GTP_MAX_TOUCH		5
 #define GTP_ESD_CHECK_CIRCLE_MS	2000
@@ -143,8 +144,6 @@
 	int ret = -EIO;
 	int retries = 0;
 
-	GTP_DEBUG_FUNC();
-
 	msgs[0].flags = !I2C_M_RD;
 	msgs[0].addr = client->addr;
 	msgs[0].len = GTP_ADDR_LENGTH;
@@ -167,7 +166,6 @@
 		if (DOZE_ENABLED == doze_status)
 			return ret;
 #endif
-		GTP_DEBUG("I2C communication timeout, resetting chip...");
 		if (init_done)
 			gtp_reset_guitar(ts, 10);
 		else
@@ -197,8 +195,6 @@
 	int ret = -EIO;
 	int retries = 0;
 
-	GTP_DEBUG_FUNC();
-
 	msg.flags = !I2C_M_RD;
 	msg.addr = client->addr;
 	msg.len = len;
@@ -215,7 +211,6 @@
 		if (DOZE_ENABLED == doze_status)
 			return ret;
 #endif
-		GTP_DEBUG("I2C communication timeout, resetting chip...");
 		if (init_done)
 			gtp_reset_guitar(ts, 10);
 		else
@@ -314,8 +309,6 @@
 {
 	unsigned long irqflags;
 
-	GTP_DEBUG_FUNC();
-
 	spin_lock_irqsave(&ts->irq_lock, irqflags);
 	if (!ts->irq_is_disabled) {
 		ts->irq_is_disabled = true;
@@ -336,8 +329,6 @@
 {
 	unsigned long irqflags = 0;
 
-	GTP_DEBUG_FUNC();
-
 	spin_lock_irqsave(&ts->irq_lock, irqflags);
 	if (ts->irq_is_disabled) {
 		enable_irq(ts->client->irq);
@@ -362,7 +353,7 @@
 		int w)
 {
 #if GTP_CHANGE_X2Y
-	GTP_SWAP(x, y);
+	swap(x, y);
 #endif
 
 	input_mt_slot(ts->input_dev, id);
@@ -371,8 +362,6 @@
 	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
 	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
 	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
-
-	GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
 }
 
 /*******************************************************
@@ -387,7 +376,6 @@
 {
 	input_mt_slot(ts->input_dev, id);
 	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
-	GTP_DEBUG("Touch id[%2d] release!", id);
 }
 
 
@@ -428,8 +416,6 @@
 	u8 doze_buf[3] = {0x81, 0x4B};
 #endif
 
-	GTP_DEBUG_FUNC();
-
 	ts = container_of(work, struct goodix_ts_data, work);
 #ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
 	if (ts->enter_update)
@@ -439,7 +425,6 @@
 #if GTP_SLIDE_WAKEUP
 	if (DOZE_ENABLED == doze_status) {
 		ret = gtp_i2c_read(ts->client, doze_buf, 3);
-		GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
 		if (ret > 0) {
 			if (doze_buf[2] == 0xAA) {
 				dev_dbg(&ts->client->dev,
@@ -516,6 +501,7 @@
 
 	if (key_value || pre_key) {
 		for (i = 0; i < GTP_MAX_KEY_NUM; i++) {
+
 #if GTP_DEBUG_ON
 			for (ret = 0; ret < 4; ++ret) {
 				if (key_codes[ret] == touch_key_array[i]) {
@@ -537,11 +523,9 @@
 #endif
 	pre_key = key_value;
 
-	GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
-
 #if GTP_WITH_PEN
 	if (pre_pen && (touch_num == 0)) {
-		GTP_DEBUG("Pen touch UP(Slot)!");
+		dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
 		input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
 		input_mt_slot(ts->input_dev, 5);
 		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
@@ -558,7 +542,8 @@
 #if GTP_WITH_PEN
 			id = coor_data[pos];
 			if (id == 128) {
-				GTP_DEBUG("Pen touch DOWN(Slot)!");
+				dev_dbg(&ts->client->dev,
+						"Pen touch DOWN(Slot)!");
 				input_x  = coor_data[pos + 1]
 					| (coor_data[pos + 2] << 8);
 				input_y  = coor_data[pos + 3]
@@ -577,7 +562,8 @@
 					ABS_MT_POSITION_Y, input_y);
 				input_report_abs(ts->input_dev,
 					ABS_MT_TOUCH_MAJOR, input_w);
-				GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]",
+				dev_dbg(&ts->client->dev,
+					"Pen/Stylus: (%d, %d)[%d]",
 					input_x, input_y, input_w);
 				pre_pen = 1;
 				pre_touch = 0;
@@ -587,8 +573,6 @@
 			touch_index |= (0x01<<id);
 		}
 
-		GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",
-			id, touch_index, pre_touch);
 		for (i = 0; i < GTP_MAX_TOUCH; i++) {
 #if GTP_WITH_PEN
 			if (pre_pen == 1)
@@ -644,8 +628,6 @@
 	struct goodix_ts_data
 		*ts = container_of(timer, struct goodix_ts_data, timer);
 
-	GTP_DEBUG_FUNC();
-
 	queue_work(ts->goodix_wq, &ts->work);
 	hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
 			HRTIMER_MODE_REL);
@@ -666,8 +648,6 @@
 {
 	struct goodix_ts_data *ts = dev_id;
 
-	GTP_DEBUG_FUNC();
-
 	gtp_irq_disable(ts);
 
 	queue_work(ts->goodix_wq, &ts->work);
@@ -699,8 +679,6 @@
 *******************************************************/
 static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
 {
-	GTP_DEBUG_FUNC();
-
 	/* This reset sequence will selcet I2C slave address */
 	gpio_direction_output(ts->pdata->reset_gpio, 0);
 	msleep(ms);
@@ -741,20 +719,17 @@
 		(u8)(GTP_REG_SLEEP >> 8),
 		(u8)GTP_REG_SLEEP, 8};
 
-	GTP_DEBUG_FUNC();
-
 #if GTP_DBL_CLK_WAKEUP
 	i2c_control_buf[2] = 0x09;
 #endif
 	gtp_irq_disable(ts);
 
-	GTP_DEBUG("entering doze mode...");
 	while (retry++ < 5) {
 		i2c_control_buf[0] = 0x80;
 		i2c_control_buf[1] = 0x46;
 		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
 		if (ret < 0) {
-			GTP_DEBUG(
+			dev_err(&ts->client->dev,
 				"failed to set doze flag into 0x8046, %d",
 				retry);
 			continue;
@@ -793,8 +768,6 @@
 		(u8)(GTP_REG_SLEEP >> 8),
 		(u8)GTP_REG_SLEEP, 5};
 
-	GTP_DEBUG_FUNC();
-
 	ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
 	usleep(5000);
 	while (retry++ < 5) {
@@ -825,8 +798,6 @@
 	u8 retry = 0;
 	s8 ret = -1;
 
-	GTP_DEBUG_FUNC();
-
 #if GTP_POWER_CTRL_SLEEP
 	gtp_reset_guitar(ts, 20);
 
@@ -897,26 +868,9 @@
 	u8 opr_buf[16];
 	u8 sensor_id = 0;
 
-	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
-	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
-	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
-	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
-	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
-	u8 cfg_info_group6[] = CTP_CFG_GROUP6;
-	u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2,
-		cfg_info_group3, cfg_info_group4,
-		cfg_info_group5, cfg_info_group6};
-
-	u8 cfg_info_len[] = {CFG_GROUP_LEN(cfg_info_group1),
-		CFG_GROUP_LEN(cfg_info_group2),
-		CFG_GROUP_LEN(cfg_info_group3),
-		CFG_GROUP_LEN(cfg_info_group4),
-		CFG_GROUP_LEN(cfg_info_group5),
-		CFG_GROUP_LEN(cfg_info_group6)};
-
-	GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
-			cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
-			cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
+	for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
+		dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d",
+			i, ts->pdata->config_data_len[i]);
 
 	ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
 	if (SUCCESS == ret) {
@@ -927,14 +881,18 @@
 			return -EINVAL;
 		}
 	}
-	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && (!cfg_info_len[3])
-		&& (!cfg_info_len[4]) && (!cfg_info_len[5])) {
+
+	for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
+		if (ts->pdata->config_data_len[i])
+			break;
+	}
+	if (i == GOODIX_MAX_CFG_GROUP) {
 		sensor_id = 0;
 	} else {
 		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
 			&sensor_id, 1);
 		if (SUCCESS == ret) {
-			if (sensor_id >= 0x06) {
+			if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
 				dev_err(&client->dev,
 					"Invalid sensor_id(0x%02X), No Config Sent!",
 					sensor_id);
@@ -946,24 +904,26 @@
 			return -EINVAL;
 		}
 	}
-	GTP_DEBUG("Sensor_ID: %d", sensor_id);
 
-	ts->gtp_cfg_len = cfg_info_len[sensor_id];
+	dev_info(&client->dev, "Sensor ID selected: %d", sensor_id);
 
-	if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+	if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH ||
+		!ts->pdata->config_data[sensor_id]) {
 		dev_err(&client->dev,
-				"Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!\n",
+				"Sensor_ID(%d) matches with NULL or invalid config group!\n",
 				sensor_id);
 		return -EINVAL;
 	}
+
 	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
 		&opr_buf[0], 1);
-
 	if (ret == SUCCESS) {
 		if (opr_buf[0] < 90) {
 			/* backup group config version */
-			grp_cfg_version = send_cfg_buf[sensor_id][0];
-			send_cfg_buf[sensor_id][0] = 0x00;
+			grp_cfg_version =
+			ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH];
+			ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH] =
+				0x00;
 			ts->fixed_cfg = 0;
 		} else {
 			/* treated as fixed config, not send config */
@@ -978,27 +938,9 @@
 		return -EINVAL;
 	}
 
-	if (ts->pdata->gtp_cfg_len) {
-		config_data = ts->pdata->config_data;
-		ts->config_data = ts->pdata->config_data;
-		ts->gtp_cfg_len = ts->pdata->gtp_cfg_len;
-	} else {
-		config_data = devm_kzalloc(&client->dev,
-			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
-				GFP_KERNEL);
-		if (!config_data) {
-			dev_err(&client->dev,
-					"Not enough memory for panel config data\n");
-			return -ENOMEM;
-		}
-
-		ts->config_data = config_data;
-		config_data[0] = GTP_REG_CONFIG_DATA >> 8;
-		config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
-		memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
-		memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
-				ts->gtp_cfg_len);
-	}
+	config_data = ts->pdata->config_data[sensor_id];
+	ts->config_data = ts->pdata->config_data[sensor_id];
+	ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
 
 #if GTP_CUSTOM_CFG
 	config_data[RESOLUTION_LOC] =
@@ -1035,7 +977,6 @@
 	}
 #endif /* !DRIVER NOT SEND CONFIG */
 
-	GTP_DEBUG_FUNC();
 	if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
 		ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
 				+ config_data[RESOLUTION_LOC];
@@ -1047,49 +988,79 @@
 	if (ret < 0)
 		dev_err(&client->dev, "%s: Send config error.\n", __func__);
 
-	GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
-			ts->abs_x_max, ts->abs_y_max,
-			ts->int_trigger_type);
-
 	msleep(20);
 	return ret;
 }
 
 /*******************************************************
 Function:
-	Read chip version.
+	Read firmware version
 Input:
 	client:  i2c device
 	version: buffer to keep ic firmware version
 Output:
 	read operation return.
-	2: succeed, otherwise: failed
+	0: succeed, otherwise: failed
 *******************************************************/
-int gtp_read_version(struct i2c_client *client, u16 *version)
+static int gtp_read_fw_version(struct i2c_client *client, u16 *version)
 {
-	int ret = -EIO;
-	u8 buf[8] = { GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff };
-
-	GTP_DEBUG_FUNC();
+	int ret = 0;
+	u8 buf[GTP_FW_VERSION_BUFFER_MAXSIZE] = {
+		GTP_REG_FW_VERSION >> 8, GTP_REG_FW_VERSION & 0xff };
 
 	ret = gtp_i2c_read(client, buf, sizeof(buf));
 	if (ret < 0) {
 		dev_err(&client->dev, "GTP read version failed.\n");
-		return ret;
+		return -EIO;
 	}
 
 	if (version)
-		*version = (buf[7] << 8) | buf[6];
+		*version = (buf[3] << 8) | buf[2];
+
+	return ret;
+}
+/*******************************************************
+Function:
+	Read and check chip id.
+Input:
+	client:  i2c device
+Output:
+	read operation return.
+	0: succeed, otherwise: failed
+*******************************************************/
+static int gtp_check_product_id(struct i2c_client *client)
+{
+	int ret = 0;
+	char product_id[GTP_PRODUCT_ID_MAXSIZE];
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+	/* 04 bytes are used for the Product-id in the register space.*/
+	u8 buf[GTP_PRODUCT_ID_BUFFER_MAXSIZE] =	{
+		GTP_REG_PRODUCT_ID >> 8, GTP_REG_PRODUCT_ID & 0xff };
+
+	ret = gtp_i2c_read(client, buf, sizeof(buf));
+	if (ret < 0) {
+		dev_err(&client->dev, "GTP read version failed.\n");
+		return -EIO;
+	}
 
 	if (buf[5] == 0x00) {
-		dev_dbg(&client->dev, "IC Version: %c%c%c_%02x%02x\n", buf[2],
-				buf[3], buf[4], buf[7], buf[6]);
+		/* copy (GTP_PRODUCT_ID_MAXSIZE - 1) from buffer. Ex: 915 */
+		strlcpy(product_id, &buf[2], GTP_PRODUCT_ID_MAXSIZE - 1);
 	} else {
 		if (buf[5] == 'S' || buf[5] == 's')
 			chip_gt9xxs = 1;
-		dev_dbg(&client->dev, "IC Version: %c%c%c%c_%02x%02x\n", buf[2],
-				buf[3], buf[4], buf[5], buf[7], buf[6]);
+		/* copy GTP_PRODUCT_ID_MAXSIZE from buffer. Ex: 915s */
+		strlcpy(product_id, &buf[2], GTP_PRODUCT_ID_MAXSIZE);
 	}
+
+	dev_info(&client->dev, "Goodix Product ID = %s\n", product_id);
+
+	if (!IS_ERR(ts->pdata->product_id))
+		ret = strcmp(product_id, ts->pdata->product_id);
+
+	if (ret != 0)
+		return -EINVAL;
+
 	return ret;
 }
 
@@ -1108,8 +1079,6 @@
 	int retry = 5;
 	int ret = -EIO;
 
-	GTP_DEBUG_FUNC();
-
 	while (retry--) {
 		ret = gtp_i2c_read(client, buf, 3);
 		if (ret > 0)
@@ -1198,9 +1167,6 @@
 	int ret;
 	const u8 irq_table[] = GTP_IRQ_TAB;
 
-	GTP_DEBUG("INT trigger type:%x, irq=%d", ts->int_trigger_type,
-			ts->client->irq);
-
 	ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
 			irq_table[ts->int_trigger_type],
 			ts->client->name, ts);
@@ -1240,8 +1206,6 @@
 	int index = 0;
 #endif
 
-	GTP_DEBUG_FUNC();
-
 	ts->input_dev = input_allocate_device();
 	if (ts->input_dev == NULL) {
 		dev_err(&ts->client->dev,
@@ -1274,7 +1238,7 @@
 #endif
 
 #if GTP_CHANGE_X2Y
-	GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
+	swap(ts->abs_x_max, ts->abs_y_max);
 #endif
 
 	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
@@ -1556,6 +1520,8 @@
 	struct property *prop;
 	u32 temp_val, num_buttons;
 	u32 button_map[MAX_BUTTONS];
+	char prop_name[PROP_NAME_SIZE];
+	int i, read_cfg_num;
 
 	rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata);
 	if (rc && (rc != -EINVAL))
@@ -1581,10 +1547,9 @@
 	if (pdata->irq_gpio < 0)
 		return pdata->irq_gpio;
 
-	rc = of_property_read_u32(np, "goodix,family-id", &temp_val);
-	if (!rc)
-		pdata->family_id = temp_val;
-	else
+	rc = of_property_read_string(np, "goodix,product-id",
+						&pdata->product_id);
+	if (rc < 0 || strlen(pdata->product_id) > GTP_PRODUCT_ID_MAXSIZE)
 		return rc;
 
 	prop = of_find_property(np, "goodix,button-map", NULL);
@@ -1602,26 +1567,32 @@
 		}
 	}
 
-	prop = of_find_property(np, "goodix,cfg-data", &pdata->gtp_cfg_len);
-	if (prop && prop->value) {
-		pdata->config_data = devm_kzalloc(dev,
-			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, GFP_KERNEL);
-		if (!pdata->config_data) {
-			dev_err(dev, "Not enough memory for panel config data\n");
+	read_cfg_num = 0;
+	for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) {
+		snprintf(prop_name, sizeof(prop_name), "goodix,cfg-data%d", i);
+		prop = of_find_property(np, prop_name,
+			&pdata->config_data_len[i]);
+		if (!prop || !prop->value) {
+			pdata->config_data_len[i] = 0;
+			pdata->config_data[i] = NULL;
+			continue;
+		}
+		pdata->config_data[i] = devm_kzalloc(dev,
+				GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+				GFP_KERNEL);
+		if (!pdata->config_data[i]) {
+			dev_err(dev,
+				"Not enough memory for panel config data %d\n",
+				i);
 			return -ENOMEM;
 		}
-
-		pdata->config_data[0] = GTP_REG_CONFIG_DATA >> 8;
-		pdata->config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
-		memset(&pdata->config_data[GTP_ADDR_LENGTH], 0,
-					GTP_CONFIG_MAX_LENGTH);
-		memcpy(&pdata->config_data[GTP_ADDR_LENGTH],
-				prop->value, pdata->gtp_cfg_len);
-	} else {
-		dev_err(dev,
-			"Unable to get configure data, default will be used.\n");
-		pdata->gtp_cfg_len = 0;
+		pdata->config_data[i][0] = GTP_REG_CONFIG_DATA >> 8;
+		pdata->config_data[i][1] = GTP_REG_CONFIG_DATA & 0xff;
+		memcpy(&pdata->config_data[i][GTP_ADDR_LENGTH],
+				prop->value, pdata->config_data_len[i]);
+		read_cfg_num++;
 	}
+	dev_dbg(dev, "%d config data read from device tree.\n", read_cfg_num);
 
 	return 0;
 }
@@ -1764,9 +1735,13 @@
 	else
 		dev_info(&client->dev, "GTP works in interrupt mode.\n");
 
-	ret = gtp_read_version(client, &version_info);
-	if (ret != 2) {
-		dev_err(&client->dev, "Read version failed.\n");
+	ret = gtp_read_fw_version(client, &version_info);
+	if (ret != 0)
+		dev_err(&client->dev, "GTP firmware version read failed.\n");
+
+	ret = gtp_check_product_id(client);
+	if (ret != 0) {
+		dev_err(&client->dev, "GTP Product id doesn't match.\n");
 		goto exit_free_irq;
 	}
 	if (ts->use_irq)
@@ -1831,7 +1806,6 @@
 {
 	struct goodix_ts_data *ts = i2c_get_clientdata(client);
 
-	GTP_DEBUG_FUNC();
 #if defined(CONFIG_FB)
 	if (fb_unregister_client(&ts->fb_notif))
 		dev_err(&client->dev,
@@ -1894,8 +1868,6 @@
 {
 	int ret = -1, i;
 
-	GTP_DEBUG_FUNC();
-
 #if GTP_ESD_PROTECT
 	ts->gtp_is_suspend = 1;
 	gtp_esd_switch(ts->client, SWITCH_OFF);
@@ -1936,8 +1908,6 @@
 {
 	int ret = -1;
 
-	GTP_DEBUG_FUNC();
-
 	ret = gtp_wakeup_sleep(ts);
 
 #if GTP_SLIDE_WAKEUP
@@ -2066,9 +2036,6 @@
 	int ret;
 	int retries = 0;
 
-	GTP_DEBUG("Init external watchdog...");
-	GTP_DEBUG_FUNC();
-
 	msg.flags = !I2C_M_RD;
 	msg.addr  = client->addr;
 	msg.len   = 4;
@@ -2101,8 +2068,6 @@
 	struct goodix_ts_data *ts = NULL;
 	u8 test[4] = {0x80, 0x40};
 
-	GTP_DEBUG_FUNC();
-
 	ts = i2c_get_clientdata(i2c_connect_client);
 
 	if (ts->gtp_is_suspend) {
@@ -2118,7 +2083,6 @@
 	for (i = 0; i < 3; i++) {
 		ret = gtp_i2c_read(ts->client, test, 4);
 
-		GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
 		if ((ret < 0)) {
 			/* IC works abnormally..*/
 			continue;
@@ -2190,7 +2154,6 @@
 {
 	int ret;
 
-	GTP_DEBUG_FUNC();
 #if GTP_ESD_PROTECT
 	INIT_DELAYED_WORK(&gtp_esd_check_work, gtp_esd_check_func);
 	gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
@@ -2209,7 +2172,6 @@
 ********************************************************/
 static void __exit goodix_ts_exit(void)
 {
-	GTP_DEBUG_FUNC();
 	i2c_del_driver(&goodix_ts_driver);
 }
 
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index c9b81e7..1fdbfa3 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -45,12 +45,13 @@
 #define GOODIX_SUSPEND_LEVEL 1
 #endif
 
+#define GOODIX_MAX_CFG_GROUP	6
 struct goodix_ts_platform_data {
 	int irq_gpio;
 	u32 irq_gpio_flags;
 	int reset_gpio;
 	u32 reset_gpio_flags;
-	u32 family_id;
+	const char *product_id;
 	u32 x_max;
 	u32 y_max;
 	u32 x_min;
@@ -61,8 +62,8 @@
 	u32 panel_maxy;
 	bool no_force_update;
 	bool i2c_pull_up;
-	int gtp_cfg_len;
-	u8 *config_data;
+	size_t config_data_len[GOODIX_MAX_CFG_GROUP];
+	u8 *config_data[GOODIX_MAX_CFG_GROUP];
 };
 struct goodix_ts_data {
 	spinlock_t irq_lock;
@@ -122,7 +123,7 @@
 /* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
 #define GTP_DBL_CLK_WAKEUP		0
 
-#define GTP_DEBUG_ON			1
+#define GTP_DEBUG_ON			0
 #define GTP_DEBUG_ARRAY_ON		0
 #define GTP_DEBUG_FUNC_ON		0
 
@@ -137,54 +138,6 @@
  *	VDDIO		NC/300K		4
  *	NC			NC/300K		5
 */
-/* Define your own default or for Sensor_ID == 0 config here */
-/* The predefined one is just a sample config,
- * which is not suitable for your tp in most cases. */
-#define CTP_CFG_GROUP1 {\
-	0x41, 0x1C, 0x02, 0xC0, 0x03, 0x0A, 0x05, 0x01, 0x01, 0x0F,\
-	0x23, 0x0F, 0x5F, 0x41, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x0A,\
-	0x28, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x00, 0x9A, 0x03, 0x25,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32, 0x00, 0x00,\
-	0x00, 0x32, 0x8C, 0x94, 0x05, 0x01, 0x05, 0x00, 0x00, 0x96,\
-	0x0C, 0x22, 0xD8, 0x0E, 0x23, 0x56, 0x11, 0x25, 0xFF, 0x13,\
-	0x28, 0xA7, 0x15, 0x2E, 0x00, 0x00, 0x10, 0x30, 0x48, 0x00,\
-	0x56, 0x4A, 0x3A, 0xFF, 0xFF, 0x16, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x01, 0x1B, 0x14, 0x0D, 0x19, 0x00, 0x00, 0x01, 0x00,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x00, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C,\
-	0x0A, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
-	0xFF, 0xFF, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24, 0x28, 0x29,\
-	0x0C, 0x0A, 0x08, 0x00, 0x02, 0x04, 0x05, 0x06, 0x0E, 0xFF,\
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
-	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x01\
-	}
-
-/* Define your config for Sensor_ID == 1 here, if needed */
-#define CTP_CFG_GROUP2 {\
-	}
-
-/* Define your config for Sensor_ID == 2 here, if needed */
-#define CTP_CFG_GROUP3 {\
-	}
-
-/* Define your config for Sensor_ID == 3 here, if needed */
-#define CTP_CFG_GROUP4 {\
-	}
-
-/* Define your config for Sensor_ID == 4 here, if needed */
-#define CTP_CFG_GROUP5 {\
-	}
-
-/* Define your config for Sensor_ID == 5 here, if needed */
-#define CTP_CFG_GROUP6 {\
-	}
 
 #define GTP_IRQ_TAB		{\
 				IRQ_TYPE_EDGE_RISING,\
@@ -206,30 +159,34 @@
 #define GTP_INT_TRIGGER		GTP_IRQ_TAB_FALLING
 #endif
 
-#define GTP_MAX_TOUCH         5
-#define GTP_ESD_CHECK_CIRCLE  2000      /* jiffy: ms */
+#define GTP_PRODUCT_ID_MAXSIZE	5
+#define GTP_PRODUCT_ID_BUFFER_MAXSIZE	6
+#define GTP_FW_VERSION_BUFFER_MAXSIZE	4
+#define GTP_MAX_TOUCH		5
+#define GTP_ESD_CHECK_CIRCLE	2000      /* jiffy: ms */
 
 /***************************PART3:OTHER define*********************************/
-#define GTP_DRIVER_VERSION		"V1.8<2013/06/08>"
-#define GTP_I2C_NAME			"Goodix-TS"
-#define GTP_POLL_TIME			10     /* jiffy: ms*/
-#define GTP_ADDR_LENGTH			2
+#define GTP_DRIVER_VERSION	"V1.8.1<2013/09/01>"
+#define GTP_I2C_NAME		"Goodix-TS"
+#define GTP_POLL_TIME		10     /* jiffy: ms*/
+#define GTP_ADDR_LENGTH		2
 #define GTP_CONFIG_MIN_LENGTH	186
 #define GTP_CONFIG_MAX_LENGTH	240
-#define FAIL					0
-#define SUCCESS					1
-#define SWITCH_OFF				0
-#define SWITCH_ON				1
+#define FAIL			0
+#define SUCCESS			1
+#define SWITCH_OFF		0
+#define SWITCH_ON		1
 
 /* Registers define */
-#define GTP_READ_COOR_ADDR		0x814E
-#define GTP_REG_SLEEP			0x8040
-#define GTP_REG_SENSOR_ID		0x814A
-#define GTP_REG_CONFIG_DATA		0x8047
-#define GTP_REG_VERSION			0x8140
+#define GTP_READ_COOR_ADDR	0x814E
+#define GTP_REG_SLEEP		0x8040
+#define GTP_REG_SENSOR_ID	0x814A
+#define GTP_REG_CONFIG_DATA	0x8047
+#define GTP_REG_FW_VERSION	0x8144
+#define GTP_REG_PRODUCT_ID	0x8140
 
-#define RESOLUTION_LOC			3
-#define TRIGGER_LOC				8
+#define RESOLUTION_LOC		3
+#define TRIGGER_LOC		8
 
 #define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
 /* Log define */
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 9f326f1..70c1307 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -32,7 +32,6 @@
 #define SHOW_PROGRESS
 #define MAX_FIRMWARE_ID_LEN 10
 #define FORCE_UPDATE false
-#define DO_LOCKDOWN false
 #define INSIDE_FIRMWARE_UPDATE
 
 #define FW_IMAGE_OFFSET 0x100
@@ -1115,7 +1114,11 @@
 	if (retval < 0)
 		return retval;
 
-	if (f01_device_status.flash_prog) {
+	if (force) {
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Force to enter flash prog mode\n",
+			__func__);
+	} else if (f01_device_status.flash_prog) {
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Already in flash prog mode\n",
 				__func__);
@@ -1475,6 +1478,9 @@
 			"%s: Erase all command written\n",
 			__func__);
 
+	if (fwu->polling_mode)
+		msleep(100);
+
 	retval = fwu_wait_for_idle(ERASE_WAIT_MS);
 	if (retval < 0)
 		return retval;
@@ -1757,7 +1763,7 @@
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -1800,7 +1806,7 @@
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -1835,7 +1841,7 @@
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -2025,6 +2031,9 @@
 static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
 		unsigned char intr_mask)
 {
+	if (!fwu)
+		return;
+
 	if (fwu->intr_mask & intr_mask)
 		fwu->interrupt_flag = true;
 
@@ -2110,6 +2119,7 @@
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Failed to alloc mem for fwu\n",
 				__func__);
+		retval = -ENOMEM;
 		goto exit;
 	}
 
@@ -2135,10 +2145,12 @@
 		dev_dbg(&rmi4_data->i2c_client->dev,
 				"%s: Failed to read PDT properties, assuming 0x00\n",
 				__func__);
+		goto exit_free_mem;
 	} else if (pdt_props.has_bsr) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Reflash for LTS not currently supported\n",
 				__func__);
+		retval = -EINVAL;
 		goto exit_free_mem;
 	}
 
@@ -2166,7 +2178,7 @@
 
 	fwu->initialized = true;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	fwu->initialized = true;
 	fwu->polling_mode = false;
 
@@ -2237,7 +2249,7 @@
 	fwu = NULL;
 
 exit:
-	return 0;
+	return retval;
 }
 
 static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 2506e05..4e75971 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -96,6 +96,8 @@
 #define F12_FINGERS_TO_SUPPORT 10
 #define MAX_F11_TOUCH_WIDTH 15
 
+#define RMI4_COORDS_ARR_SIZE 4
+
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
 		unsigned short length);
@@ -1053,9 +1055,9 @@
 			wy = finger_data->wy;
 #endif
 
-			if (rmi4_data->board->x_flip)
+			if (rmi4_data->flip_x)
 				x = rmi4_data->sensor_max_x - x;
-			if (rmi4_data->board->y_flip)
+			if (rmi4_data->flip_y)
 				y = rmi4_data->sensor_max_y - y;
 
 			dev_dbg(&rmi4_data->i2c_client->dev,
@@ -1332,6 +1334,50 @@
 }
 
 #ifdef CONFIG_OF
+static int synaptics_rmi4_get_dt_coords(struct device *dev, char *name,
+				struct synaptics_rmi4_platform_data *pdata)
+{
+	u32 coords[RMI4_COORDS_ARR_SIZE];
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int coords_size, rc;
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	coords_size = prop->length / sizeof(u32);
+	if (coords_size != RMI4_COORDS_ARR_SIZE) {
+		dev_err(dev, "invalid %s\n", name);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_array(np, name, coords, coords_size);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read %s\n", name);
+		return rc;
+	}
+
+	if (strcmp(name, "synaptics,panel-coords") == 0) {
+		pdata->panel_minx = coords[0];
+		pdata->panel_miny = coords[1];
+		pdata->panel_maxx = coords[2];
+		pdata->panel_maxy = coords[3];
+	} else if (strcmp(name, "synaptics,display-coords") == 0) {
+		pdata->disp_minx = coords[0];
+		pdata->disp_miny = coords[1];
+		pdata->disp_maxx = coords[2];
+		pdata->disp_maxy = coords[3];
+	} else {
+		dev_err(dev, "unsupported property %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int synaptics_rmi4_parse_dt(struct device *dev,
 				struct synaptics_rmi4_platform_data *rmi4_pdata)
 {
@@ -1349,21 +1395,26 @@
 			"synaptics,disable-gpios");
 	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
 	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
+	rmi4_pdata->do_lockdown = of_property_read_bool(np,
+			"synaptics,do-lockdown");
 
-	rc = of_property_read_u32(np, "synaptics,panel-x", &temp_val);
-	if (rc && (rc != -EINVAL)) {
-		dev_err(dev, "Unable to read panel X dimension\n");
+	rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,display-coords",
+				rmi4_pdata);
+	if (rc && (rc != -EINVAL))
 		return rc;
-	} else {
-		rmi4_pdata->panel_x = temp_val;
-	}
 
-	rc = of_property_read_u32(np, "synaptics,panel-y", &temp_val);
-	if (rc && (rc != -EINVAL)) {
-		dev_err(dev, "Unable to read panel Y dimension\n");
+	rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,panel-coords",
+				rmi4_pdata);
+	if (rc && (rc != -EINVAL))
 		return rc;
-	} else {
-		rmi4_pdata->panel_y = temp_val;
+
+	rmi4_pdata->reset_delay = RESET_DELAY;
+	rc = of_property_read_u32(np, "synaptics,reset-delay", &temp_val);
+	if (!rc)
+		rmi4_pdata->reset_delay = temp_val;
+	else if (rc != -EINVAL) {
+		dev_err(dev, "Unable to read reset delay\n");
+		return rc;
 	}
 
 	rc = of_property_read_string(np, "synaptics,fw-image-name",
@@ -1819,11 +1870,10 @@
 	const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
 
 	if (!pdata->capacitance_button_map) {
-		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: capacitance_button_map is" \
-				"NULL in board file\n",
+		dev_info(&rmi4_data->i2c_client->dev,
+				"%s: capacitance_button_map not in use\n",
 				__func__);
-		return -ENODEV;
+		return 0;
 	} else if (!pdata->capacitance_button_map->map) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Button map is missing in board file\n",
@@ -2258,7 +2308,7 @@
 		return retval;
 	}
 
-	msleep(RESET_DELAY);
+	msleep(rmi4_data->board->reset_delay);
 	return retval;
 };
 
@@ -2328,8 +2378,12 @@
 				link) {
 			if ((exp_fhandler->func_init != NULL) &&
 					(exp_fhandler->inserted == false)) {
-				exp_fhandler->func_init(rmi4_data);
-				exp_fhandler->inserted = true;
+				if (exp_fhandler->func_init(rmi4_data) < 0) {
+					list_del(&exp_fhandler->link);
+					kfree(exp_fhandler);
+				} else {
+					exp_fhandler->inserted = true;
+				}
 			} else if ((exp_fhandler->func_init == NULL) &&
 					(exp_fhandler->inserted == true)) {
 				exp_fhandler->func_remove(rmi4_data);
@@ -2603,7 +2657,7 @@
 			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(RESET_DELAY);
+			msleep(rmi4_data->board->reset_delay);
 		} else
 			synaptics_rmi4_reset_command(rmi4_data);
 
@@ -2776,12 +2830,32 @@
 		goto err_free_gpios;
 	}
 
+	if (rmi4_data->board->disp_maxx)
+		rmi4_data->disp_maxx = rmi4_data->board->disp_maxx;
+	else
+		rmi4_data->disp_maxx = rmi4_data->sensor_max_x;
+
+	if (rmi4_data->board->disp_maxy)
+		rmi4_data->disp_maxy = rmi4_data->board->disp_maxy;
+	else
+		rmi4_data->disp_maxy = rmi4_data->sensor_max_y;
+
+	if (rmi4_data->board->disp_minx)
+		rmi4_data->disp_minx = rmi4_data->board->disp_minx;
+	else
+		rmi4_data->disp_minx = 0;
+
+	if (rmi4_data->board->disp_miny)
+		rmi4_data->disp_miny = rmi4_data->board->disp_miny;
+	else
+		rmi4_data->disp_miny = 0;
+
 	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_X, 0,
-			rmi4_data->sensor_max_x, 0, 0);
+			ABS_MT_POSITION_X, rmi4_data->disp_minx,
+			rmi4_data->disp_maxx, 0, 0);
 	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_Y, 0,
-			rmi4_data->sensor_max_y, 0, 0);
+			ABS_MT_POSITION_Y, rmi4_data->disp_miny,
+			rmi4_data->disp_maxy, 0, 0);
 	input_set_abs_params(rmi4_data->input_dev,
 			ABS_PRESSURE, 0, 255, 0, 0);
 #ifdef REPORT_2D_W
@@ -3391,17 +3465,6 @@
 	rmi4_data->touch_stopped = false;
 	synaptics_rmi4_irq_enable(rmi4_data, true);
 
-	if (rmi4_data->board->power_down_enable ||
-			rmi4_data->board->disable_gpios) {
-		retval = synaptics_rmi4_reset_device(rmi4_data);
-		if (retval < 0) {
-			dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Failed to issue reset command, " \
-				"rc = %d\n", __func__, retval);
-			return retval;
-		}
-	}
-
 	rmi4_data->suspended = false;
 
 	return 0;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 677a2fe..ef39bb7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -186,6 +186,10 @@
  * @irq: attention interrupt
  * @sensor_max_x: sensor maximum x value
  * @sensor_max_y: sensor maximum y value
+ * @disp_maxx: max x value of display
+ * @disp_maxy: max y value of display
+ * @disp_minx: min x value of display
+ * @disp_miny: min y value of display
  * @irq_enabled: flag for indicating interrupt enable status
  * @touch_stopped: flag to stop interrupt thread processing
  * @fingers_on_2d: flag to indicate presence of fingers in 2d area
@@ -230,6 +234,10 @@
 	int irq;
 	int sensor_max_x;
 	int sensor_max_y;
+	int disp_maxx;
+	int disp_maxy;
+	int disp_minx;
+	int disp_miny;
 	bool irq_enabled;
 	bool touch_stopped;
 	bool fingers_on_2d;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 6324dff..8e70129 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -45,10 +45,22 @@
 
 	  If unsure, say N here.
 
+# MSM IOMMU sync lock support
+config MSM_IOMMU_SYNC
+	bool "MSM IOMMU Sync Lock Support"
+	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930 || ARCH_MSM8610) && MSM_IOMMU_V0
+	help
+	  Say Y here if you want the IOMMU to grab a remote spinlock to ensure
+	  synchronization between IOMMU accesses by CPU and other exectution
+	  environments in the SoC.
+
+	  If unsure, say N here.
+
 # MSM IOMMU CPU-GPU sync programming support
 config MSM_IOMMU_GPU_SYNC
 	bool "MSM IOMMU CPU-GPU Sync Support"
-	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU_V0 && MSM_REMOTE_SPINLOCK_SFPB
+	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU_V0
+	select  MSM_IOMMU_SYNC
 	help
 	  Say Y here if you want to synchronize access to IOMMU configuration
 	  port between CPU and GPU. CPU will grab a remote spinlock before
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 49bfdb8..99d071b 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -83,7 +83,7 @@
 
 static struct msm_iommu_remote_lock msm_iommu_remote_lock;
 
-#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+#ifdef CONFIG_MSM_IOMMU_SYNC
 static void _msm_iommu_remote_spin_lock_init(void)
 {
 	msm_iommu_remote_lock.lock = smem_alloc(SMEM_SPINLOCK_ARRAY, 32);
@@ -91,8 +91,11 @@
 			sizeof(*msm_iommu_remote_lock.lock));
 }
 
-void msm_iommu_remote_p0_spin_lock(void)
+void msm_iommu_remote_p0_spin_lock(unsigned int need_lock)
 {
+	if (!need_lock)
+		return;
+
 	msm_iommu_remote_lock.lock->flag[PROC_APPS] = 1;
 	msm_iommu_remote_lock.lock->turn = 1;
 
@@ -103,8 +106,11 @@
 		cpu_relax();
 }
 
-void msm_iommu_remote_p0_spin_unlock(void)
+void msm_iommu_remote_p0_spin_unlock(unsigned int need_lock)
 {
+	if (!need_lock)
+		return;
+
 	smp_mb();
 
 	msm_iommu_remote_lock.lock->flag[PROC_APPS] = 0;
@@ -200,14 +206,16 @@
 	return msm_iommu_lock_initialize();
 }
 
-static void _iommu_lock_acquire(void)
+static void _iommu_lock_acquire(unsigned int need_extra_lock)
 {
-	msm_iommu_lock();
+	msm_iommu_mutex_lock();
+	msm_iommu_remote_spin_lock(need_extra_lock);
 }
 
-static void _iommu_lock_release(void)
+static void _iommu_lock_release(unsigned int need_extra_lock)
 {
-	msm_iommu_unlock();
+	msm_iommu_remote_spin_unlock(need_extra_lock);
+	msm_iommu_mutex_unlock();
 }
 
 struct iommu_access_ops iommu_access_ops_v0 = {
@@ -241,7 +249,7 @@
 		if (ret)
 			goto fail;
 
-		msm_iommu_remote_spin_lock();
+		msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
 
 		asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
 					   ctx_drvdata->num);
@@ -250,7 +258,7 @@
 			   asid | (va & TLBIVA_VA));
 		mb();
 
-		msm_iommu_remote_spin_unlock();
+		msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
 
 		__disable_clocks(iommu_drvdata);
 	}
@@ -278,7 +286,7 @@
 		if (ret)
 			goto fail;
 
-		msm_iommu_remote_spin_lock();
+		msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
 
 		asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
 					   ctx_drvdata->num);
@@ -286,7 +294,7 @@
 		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
 		mb();
 
-		msm_iommu_remote_spin_unlock();
+		msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
 
 		__disable_clocks(iommu_drvdata);
 	}
@@ -318,13 +326,16 @@
 	mb();
 }
 
-static void __program_context(void __iomem *base, void __iomem *glb_base,
+static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
 			      int ctx, int ncb, phys_addr_t pgtable,
 			      int redirect, int ttbr_split)
 {
+	void __iomem *base = iommu_drvdata->base;
+	void __iomem *glb_base = iommu_drvdata->glb_base;
 	unsigned int prrr, nmrr;
 	int i, j, found;
-	msm_iommu_remote_spin_lock();
+
+	msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
 
 	__reset_context(base, glb_base, ctx);
 
@@ -416,7 +427,7 @@
 	SET_M(base, ctx, 1);
 	mb();
 
-	msm_iommu_remote_spin_unlock();
+	msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
 }
 
 static int msm_iommu_domain_init(struct iommu_domain *domain, int flags)
@@ -526,7 +537,7 @@
 	if (ret)
 		goto unlock;
 
-	__program_context(iommu_drvdata->base, iommu_drvdata->glb_base,
+	__program_context(iommu_drvdata,
 			  ctx_drvdata->num, iommu_drvdata->ncb,
 			  __pa(priv->pt.fl_table), priv->pt.redirect,
 			  iommu_drvdata->ttbr_split);
@@ -577,7 +588,7 @@
 	if (ret)
 		goto unlock;
 
-	msm_iommu_remote_spin_lock();
+	msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
 
 	SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
 		    GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
@@ -585,7 +596,7 @@
 	__reset_context(iommu_drvdata->base, iommu_drvdata->glb_base,
 			ctx_drvdata->num);
 
-	msm_iommu_remote_spin_unlock();
+	msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
 
 	__disable_clocks(iommu_drvdata);
 
@@ -1246,7 +1257,7 @@
 	if (ret)
 		goto fail;
 
-	msm_iommu_remote_spin_lock();
+	msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
 
 	SET_V2PPR(base, ctx, va & V2Pxx_VA);
 
@@ -1262,7 +1273,7 @@
 	if (GET_FAULT(base, ctx))
 		ret = 0;
 
-	msm_iommu_remote_spin_unlock();
+	msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
 
 	__disable_clocks(iommu_drvdata);
 fail:
@@ -1324,7 +1335,7 @@
 	if (ret)
 		goto fail;
 
-	msm_iommu_remote_spin_lock();
+	msm_iommu_remote_spin_lock(drvdata->needs_rem_spinlock);
 
 	fsr = GET_FSR(base, num);
 
@@ -1357,7 +1368,7 @@
 	} else
 		ret = IRQ_NONE;
 
-	msm_iommu_remote_spin_unlock();
+	msm_iommu_remote_spin_unlock(drvdata->needs_rem_spinlock);
 
 	__disable_clocks(drvdata);
 fail:
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index b9c4cae..c81aa0ac 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -123,12 +123,12 @@
 	clk_disable_unprepare(drvdata->pclk);
 }
 
-static void _iommu_lock_acquire(void)
+static void _iommu_lock_acquire(unsigned int need_extra_lock)
 {
 	mutex_lock(&msm_iommu_lock);
 }
 
-static void _iommu_lock_release(void)
+static void _iommu_lock_release(unsigned int need_extra_lock)
 {
 	mutex_unlock(&msm_iommu_lock);
 }
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 2d0fba2..9382e52 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -216,6 +216,12 @@
 	drvdata->sec_id = -1;
 	drvdata->ttbr_split = 0;
 
+	drvdata->needs_rem_spinlock = of_property_read_bool(pdev->dev.of_node,
+					"qcom,msm-enable-remote-spinlock");
+
+	if (drvdata->needs_rem_spinlock)
+		pr_info("%s enabled remote spinlock\n", drvdata->name);
+
 	ret = of_platform_populate(pdev->dev.of_node,
 				   msm_iommu_v0_ctx_match_table,
 				   NULL, &pdev->dev);
diff --git a/drivers/iommu/msm_iommu_perfmon-v0.c b/drivers/iommu/msm_iommu_perfmon-v0.c
index 1073623..b08a9ec 100644
--- a/drivers/iommu/msm_iommu_perfmon-v0.c
+++ b/drivers/iommu/msm_iommu_perfmon-v0.c
@@ -176,9 +176,9 @@
 		goto out;
 	}
 
-	iommu->ops->iommu_lock_acquire();
+	iommu->ops->iommu_lock_acquire(1);
 	iommu_pm_check_for_overflow(pmon);
-	iommu->ops->iommu_lock_release();
+	iommu->ops->iommu_lock_release(1);
 
 	mutex_unlock(&pmon->lock);
 
diff --git a/drivers/iommu/msm_iommu_perfmon-v1.c b/drivers/iommu/msm_iommu_perfmon-v1.c
index 7d6dd34..2b55184 100644
--- a/drivers/iommu/msm_iommu_perfmon-v1.c
+++ b/drivers/iommu/msm_iommu_perfmon-v1.c
@@ -151,9 +151,9 @@
 		goto out;
 	}
 
-	iommu->ops->iommu_lock_acquire();
+	iommu->ops->iommu_lock_acquire(0);
 	iommu_pm_check_for_overflow(pmon);
-	iommu->ops->iommu_lock_release();
+	iommu->ops->iommu_lock_release(0);
 
 	mutex_unlock(&pmon->lock);
 
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index 958c6ca..503d4ab 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -188,11 +188,11 @@
 
 	if (event_class == MSM_IOMMU_PMU_NO_EVENT_CLASS) {
 		if (iommu->hw_ops->is_hw_access_OK(pmon)) {
-			iommu->ops->iommu_lock_acquire();
+			iommu->ops->iommu_lock_acquire(1);
 			iommu->hw_ops->counter_disable(iommu, counter);
 			iommu->hw_ops->ovfl_int_disable(iommu, counter);
 			iommu->hw_ops->set_event_class(pmon, count_no, 0);
-			iommu->ops->iommu_lock_release();
+			iommu->ops->iommu_lock_release(1);
 		}
 		counter->overflow_count = 0;
 		counter->value = 0;
@@ -200,12 +200,12 @@
 		counter->overflow_count = 0;
 		counter->value = 0;
 		if (iommu->hw_ops->is_hw_access_OK(pmon)) {
-			iommu->ops->iommu_lock_acquire();
+			iommu->ops->iommu_lock_acquire(1);
 			iommu->hw_ops->set_event_class(pmon, count_no,
 					event_class);
 			iommu->hw_ops->ovfl_int_enable(iommu, counter);
 			iommu->hw_ops->counter_enable(iommu, counter);
-			iommu->ops->iommu_lock_release();
+			iommu->ops->iommu_lock_release(1);
 		}
 	}
 }
@@ -261,9 +261,9 @@
 	iommu->ops->iommu_clk_on(iommu_drvdata);
 
 	/* Reset counters in HW */
-	iommu->ops->iommu_lock_acquire();
+	iommu->ops->iommu_lock_acquire(1);
 	iommu->hw_ops->reset_counters(&pmon->iommu);
-	iommu->ops->iommu_lock_release();
+	iommu->ops->iommu_lock_release(1);
 
 	/* Reset SW counters */
 	iommu_pm_reset_counts(pmon);
@@ -272,7 +272,7 @@
 
 	iommu_pm_set_all_counters(pmon);
 
-	iommu->ops->iommu_lock_acquire();
+	iommu->ops->iommu_lock_acquire(1);
 
 	/* enable all counter group */
 	for (i = 0; i < pmon->num_groups; ++i)
@@ -280,7 +280,7 @@
 
 	/* enable global counters */
 	iommu->hw_ops->enable_pm(iommu);
-	iommu->ops->iommu_lock_release();
+	iommu->ops->iommu_lock_release(1);
 
 	pr_info("%s: TLB performance monitoring turned ON\n",
 		pmon->iommu.iommu_name);
@@ -295,7 +295,7 @@
 
 	pmon->enabled = 0;
 
-	iommu->ops->iommu_lock_acquire();
+	iommu->ops->iommu_lock_acquire(1);
 
 	/* disable global counters */
 	iommu->hw_ops->disable_pm(iommu);
@@ -310,7 +310,7 @@
 	/* Update cached copy of counters before turning off power */
 	iommu_pm_read_all_counters(pmon);
 
-	iommu->ops->iommu_lock_release();
+	iommu->ops->iommu_lock_release(1);
 	iommu->ops->iommu_clk_off(iommu_drvdata);
 	iommu->ops->iommu_bus_vote(iommu_drvdata, 0);
 	iommu->ops->iommu_power_off(iommu_drvdata);
@@ -341,9 +341,9 @@
 	mutex_lock(&pmon->lock);
 
 	if (iommu->hw_ops->is_hw_access_OK(pmon)) {
-		iommu->ops->iommu_lock_acquire();
+		iommu->ops->iommu_lock_acquire(1);
 		counter->value = iommu->hw_ops->read_counter(counter);
-		iommu->ops->iommu_lock_release();
+		iommu->ops->iommu_lock_release(1);
 	}
 	full_count = (unsigned long long) counter->value +
 		     ((unsigned long long)counter->overflow_count *
@@ -448,9 +448,9 @@
 		rv = kstrtoul(buf, 10, &cmd);
 		if (!rv && (cmd == 1)) {
 			if (iommu->hw_ops->is_hw_access_OK(pmon)) {
-				iommu->ops->iommu_lock_acquire();
+				iommu->ops->iommu_lock_acquire(1);
 				iommu->hw_ops->reset_counters(&pmon->iommu);
-				iommu->ops->iommu_lock_release();
+				iommu->ops->iommu_lock_release(1);
 			}
 			iommu_pm_reset_counts(pmon);
 			pr_info("TLB performance counters reset\n");
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 474efdf..5a1806e 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -194,7 +194,7 @@
 	struct msm_scm_fault_regs_dump *regs;
 	int tmp, ret = IRQ_HANDLED;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 
 	BUG_ON(!pdev);
 
@@ -266,7 +266,7 @@
 free_regs:
 	kfree(regs);
 lock_release:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 	return ret;
 }
 
@@ -510,12 +510,12 @@
 {
 	struct msm_iommu_priv *priv;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 	priv = domain->priv;
 	domain->priv = NULL;
 
 	kfree(priv);
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 }
 
 static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -526,7 +526,7 @@
 	struct msm_iommu_ctx_drvdata *tmp_drvdata;
 	int ret = 0;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 
 	priv = domain->priv;
 	if (!priv || !dev) {
@@ -581,12 +581,12 @@
 	ctx_drvdata->attached_domain = domain;
 	++iommu_drvdata->ctx_attach_count;
 
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 
 	msm_iommu_attached(dev->parent);
 	return ret;
 fail:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 	return ret;
 }
 
@@ -598,7 +598,7 @@
 
 	msm_iommu_detached(dev->parent);
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 	if (!dev)
 		goto fail;
 
@@ -614,7 +614,7 @@
 	BUG_ON(iommu_drvdata->ctx_attach_count == 0);
 	--iommu_drvdata->ctx_attach_count;
 fail:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 }
 
 static int get_drvdata(struct iommu_domain *domain,
@@ -644,7 +644,7 @@
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	int ret = 0;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 
 	ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
 	if (ret)
@@ -655,7 +655,7 @@
 					va, pa, len);
 	iommu_access_ops->iommu_clk_off(iommu_drvdata);
 fail:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 	return ret;
 }
 
@@ -666,7 +666,7 @@
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	int ret = -ENODEV;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 
 	ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
 	if (ret)
@@ -677,7 +677,7 @@
 					va, len);
 	iommu_access_ops->iommu_clk_off(iommu_drvdata);
 fail:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 
 	/* the IOMMU API requires us to return how many bytes were unmapped */
 	len = ret ? 0 : len;
@@ -692,7 +692,7 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 
 	ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
 	if (ret)
@@ -702,7 +702,7 @@
 						va, sg, len);
 	iommu_access_ops->iommu_clk_off(iommu_drvdata);
 fail:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 	return ret;
 }
 
@@ -714,7 +714,7 @@
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	int ret;
 
-	iommu_access_ops->iommu_lock_acquire();
+	iommu_access_ops->iommu_lock_acquire(0);
 
 	ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
 	if (ret)
@@ -725,7 +725,7 @@
 	iommu_access_ops->iommu_clk_off(iommu_drvdata);
 
 fail:
-	iommu_access_ops->iommu_lock_release();
+	iommu_access_ops->iommu_lock_release(0);
 	return 0;
 }
 
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index ecab061..bf59d03 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -23,6 +23,7 @@
 #include <linux/spmi.h>
 #include <linux/qpnp/pwm.h>
 #include <linux/workqueue.h>
+#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
@@ -43,6 +44,7 @@
 #define WLED_HIGH_POLE_CAP_REG(base)		(base + 0x58)
 #define WLED_CURR_SINK_MASK		0xE0
 #define WLED_CURR_SINK_SHFT		0x05
+#define WLED_DISABLE_ALL_SINKS		0x00
 #define WLED_SWITCH_FREQ_MASK		0x0F
 #define WLED_OVP_VAL_MASK		0x03
 #define WLED_OVP_VAL_BIT_SHFT		0x00
@@ -58,6 +60,8 @@
 #define WLED_CTL_DLY_STEP		200
 #define WLED_CTL_DLY_MAX		1400
 #define WLED_MAX_CURR			25
+#define WLED_NO_CURRENT			0x00
+#define WLED_OVP_DELAY			1000
 #define WLED_MSB_MASK			0x0F
 #define WLED_MAX_CURR_MASK		0x1F
 #define WLED_OP_FDBCK_MASK		0x07
@@ -73,6 +77,9 @@
 #define WLED_SYNC_VAL			0x07
 #define WLED_SYNC_RESET_VAL		0x00
 
+#define PMIC_VER_8026			0x04
+#define PMIC_VERSION_REG		0x0105
+
 #define WLED_DEFAULT_STRINGS		0x01
 #define WLED_DEFAULT_OVP_VAL		0x02
 #define WLED_BOOST_LIM_DEFAULT		0x03
@@ -337,6 +344,7 @@
 	u8	ctrl_delay_us;
 	u8	switch_freq;
 	u8	op_fdbck;
+	u8	pmic_version;
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
 };
@@ -511,16 +519,86 @@
 	pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
 }
 
+static int qpnp_wled_sync(struct qpnp_led_data *led)
+{
+	int rc;
+	u8 val;
+
+	/* sync */
+	val = WLED_SYNC_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED set sync reg failed(%d)\n", rc);
+		return rc;
+	}
+
+	val = WLED_SYNC_RESET_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED reset sync reg failed(%d)\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
 static int qpnp_wled_set(struct qpnp_led_data *led)
 {
 	int rc, duty, level;
-	u8 val, i, num_wled_strings;
+	u8 val, i, num_wled_strings, sink_val;
+
+	num_wled_strings = led->wled_cfg->num_strings;
 
 	level = led->cdev.brightness;
 
 	if (level > WLED_MAX_LEVEL)
 		level = WLED_MAX_LEVEL;
 	if (level == 0) {
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, WLED_NO_CURRENT);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED read sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
+		if (led->wled_cfg->pmic_version == PMIC_VER_8026) {
+			val = WLED_DISABLE_ALL_SINKS;
+			rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+				led->spmi_dev->sid,
+				WLED_CURR_SINK_REG(led->base), &val, 1);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"WLED write sink reg failed(%d)\n", rc);
+				return rc;
+			}
+
+			usleep(WLED_OVP_DELAY);
+		}
+
 		val = WLED_BOOST_OFF;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
 			led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
@@ -530,6 +608,35 @@
 				"WLED write ctrl reg failed(%d)\n", rc);
 			return rc;
 		}
+
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, led->max_current);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED write sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
 	} else {
 		val = WLED_BOOST_ON;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
@@ -544,8 +651,6 @@
 
 	duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
 
-	num_wled_strings = led->wled_cfg->num_strings;
-
 	/* program brightness control registers */
 	for (i = 0; i < num_wled_strings; i++) {
 		rc = qpnp_led_masked_write(led,
@@ -567,22 +672,9 @@
 		}
 	}
 
-	/* sync */
-	val = WLED_SYNC_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
+	rc = qpnp_wled_sync(led);
 	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED set sync reg failed(%d)\n", rc);
-		return rc;
-	}
-
-	val = WLED_SYNC_RESET_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED reset sync reg failed(%d)\n", rc);
+		dev_err(&led->spmi_dev->dev, "WLED sync failed(%d)\n", rc);
 		return rc;
 	}
 	return 0;
@@ -2489,6 +2581,13 @@
 		return -ENOMEM;
 	}
 
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		PMIC_VERSION_REG, &led->wled_cfg->pmic_version, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read pmic ver, rc(%d)\n", rc);
+	}
+
 	led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
 	rc = of_property_read_u32(node, "qcom,num-strings", &val);
 	if (!rc)
diff --git a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
index 78d15d9..d9fba33 100644
--- a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
+++ b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
@@ -2777,40 +2777,6 @@
 	return rc;
 }
 
-static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
-{
-	struct msm_cam_config_dev *config_cam = fp->private_data;
-	int rc = 0;
-	int phyaddr;
-	int retval;
-	unsigned long size;
-
-	D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
-	phyaddr = (int)config_cam->mem_map.cookie;
-	if (!phyaddr) {
-		pr_err("%s: no physical memory to map", __func__);
-		return -EFAULT;
-	}
-	memset(&config_cam->mem_map, 0,
-		sizeof(struct msm_mem_map_info));
-	size = vma->vm_end - vma->vm_start;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	retval = remap_pfn_range(vma, vma->vm_start,
-					phyaddr >> PAGE_SHIFT,
-					size, vma->vm_page_prot);
-	if (retval) {
-		pr_err("%s: remap failed, rc = %d",
-					__func__, retval);
-		rc = -ENOMEM;
-		goto end;
-	}
-	D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
-			__func__, (uint32_t)phyaddr,
-			vma->vm_start, vma->vm_end, vma->vm_pgoff);
-end:
-	return rc;
-}
-
 static int msm_open_config(struct inode *inode, struct file *fp)
 {
 	int rc;
@@ -3081,12 +3047,6 @@
 		rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
 		break;
 
-	case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
-		if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
-				sizeof(struct msm_mem_map_info)))
-			rc = -EINVAL;
-		break;
-
 	case MSM_CAM_IOCTL_SET_MCTL_SDEV:{
 		struct msm_mctl_set_sdev_data set_data;
 		if (copy_from_user(&set_data, (void __user *)arg,
@@ -3148,7 +3108,6 @@
 	.open  = msm_open_config,
 	.poll  = msm_poll_config,
 	.unlocked_ioctl = msm_ioctl_config,
-	.mmap	= msm_mmap_config,
 	.release = msm_close_config,
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 4668d02..262fb38 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -119,6 +119,15 @@
 		snapshot config = 4208 x 3120 at 24 fps,
 		Video HDR support.
 
+config IMX134
+	bool "Sensor IMX134 (BAYER 8M)"
+	depends on MSMB_CAMERA
+	---help---
+		Sony 8 MP Bayer Sensor with auto focus, uses
+		4 mipi lanes full resolution @30fps and
+		HFR @60fps and @120fps
+		Video HDR support.
+
 config OV2720
 	bool "Sensor OV2720 (BAYER 2M)"
 	depends on MSMB_CAMERA
@@ -191,6 +200,15 @@
 		snapshot config = 3264 * 2448 at 18 fps.
 		2 lanes max fps is 18, 4 lanes max fps is 24.
 
+config OV8865
+	bool "OmniVision OV8865 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		4 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 30 fps.
+		Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224
+
 config s5k4e1
 	bool "Sensor s5k4e1 (BAYER 5MP)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 4aa423f..87bffde 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/delay.h>
+#include <linux/avtimer.h>
 #include <media/v4l2-subdev.h>
 #include <media/msmb_isp.h>
 #include <mach/msm_bus.h>
@@ -35,6 +36,10 @@
 #define MAX_INIT_FRAME_DROP 31
 #define ISP_Q2 (1 << 2)
 
+#define AVTIMER_MSW_PHY_ADDR 0xFE05300C
+#define AVTIMER_LSW_PHY_ADDR 0xFE053008
+#define AVTIMER_ITERATION_CTR 16
+
 #define VFE_PING_FLAG 0xFFFFFFFF
 #define VFE_PONG_FLAG 0x0
 
@@ -69,6 +74,8 @@
 struct msm_isp_timestamp {
 	/*Monotonic clock for v4l2 buffer*/
 	struct timeval buf_time;
+	/*Monotonic clock for VT */
+	struct timeval vt_time;
 	/*Wall clock for userspace event*/
 	struct timeval event_time;
 };
@@ -263,7 +270,7 @@
 	uint32_t stream_handle;
 	uint8_t buf_divert;
 	enum msm_vfe_axi_stream_type stream_type;
-
+	uint32_t vt_enable;
 	uint32_t frame_based;
 	uint32_t framedrop_period;
 	uint32_t framedrop_pattern;
@@ -436,6 +443,9 @@
 	int dump_reg;
 	int vfe_clk_idx;
 	uint32_t vfe_open_cnt;
+	uint8_t vt_enable;
+	void __iomem *p_avtimer_msw;
+	void __iomem *p_avtimer_lsw;
 };
 
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index a6972e4..a8da26d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -24,7 +24,8 @@
 
 #define VFE32_BURST_LEN 2
 #define VFE32_UB_SIZE 1024
-#define VFE32_EQUAL_SLICE_UB 198
+#define VFE32_EQUAL_SLICE_UB 194
+#define VFE32_AXI_SLICE_UB 792
 #define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
 #define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
 #define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
@@ -319,6 +320,7 @@
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct msm_isp_timestamp *ts)
 {
+	uint32_t rdi_status;
 	if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
 		return;
 
@@ -331,6 +333,18 @@
 	if (irq_status1 & BIT(28))
 		msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts);
 
+	if (vfe_dev->axi_data.stream_update) {
+		rdi_status = msm_camera_io_r(vfe_dev->vfe_base +
+						VFE32_XBAR_BASE(0));
+		rdi_status |= msm_camera_io_r(vfe_dev->vfe_base +
+						VFE32_XBAR_BASE(4));
+
+		if (((rdi_status & BIT(7)) || (rdi_status & BIT(7)) ||
+			(rdi_status & BIT(7)) || (rdi_status & BIT(7))) &&
+			(!(irq_status0 & 0x20)))
+			return;
+	}
+
 	if (vfe_dev->axi_data.stream_update)
 		msm_isp_axi_stream_update(vfe_dev);
 	if (atomic_read(&vfe_dev->stats_data.stats_update))
@@ -759,11 +773,21 @@
 {
 	int i;
 	uint32_t ub_offset = 0;
+	uint32_t final_ub_slice_size;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
-		msm_camera_io_w(ub_offset << 16 | (VFE32_EQUAL_SLICE_UB - 1),
-			vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC);
-		ub_offset += VFE32_EQUAL_SLICE_UB;
+		if (ub_offset + VFE32_EQUAL_SLICE_UB > VFE32_AXI_SLICE_UB) {
+			final_ub_slice_size = VFE32_AXI_SLICE_UB - ub_offset;
+			msm_camera_io_w(ub_offset << 16 |
+				(final_ub_slice_size - 1), vfe_dev->vfe_base +
+				VFE32_WM_BASE(i) + 0xC);
+			ub_offset += final_ub_slice_size;
+		} else {
+			msm_camera_io_w(ub_offset << 16 |
+				(VFE32_EQUAL_SLICE_UB - 1), vfe_dev->vfe_base +
+				VFE32_WM_BASE(i) + 0xC);
+			ub_offset += VFE32_EQUAL_SLICE_UB;
+		}
 	}
 }
 
@@ -1023,7 +1047,7 @@
 }
 
 struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = {
-	.num_wm = 4,
+	.num_wm = 5,
 	.num_comp_mask = 3,
 	.num_rdi = 3,
 	.num_rdi_master = 3,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f547b0e..4f3094a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -524,7 +524,16 @@
 	}
 
 	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
-
+	stream_info->vt_enable = stream_cfg_cmd->vt_enable;
+	if (stream_info->vt_enable) {
+		vfe_dev->vt_enable = stream_info->vt_enable;
+	#ifdef CONFIG_MSM_AVTIMER
+		avcs_core_open();
+		avcs_core_disable_power_collapse(1);
+	#endif
+		vfe_dev->p_avtimer_lsw = ioremap(AVTIMER_LSW_PHY_ADDR, 4);
+		vfe_dev->p_avtimer_msw = ioremap(AVTIMER_MSW_PHY_ADDR, 4);
+	}
 	if (stream_info->num_planes > 1) {
 		msm_isp_axi_reserve_comp_mask(
 			&vfe_dev->axi_data, stream_info);
@@ -783,15 +792,21 @@
 {
 	int rc;
 	struct msm_isp_event_data buf_event;
+	struct timeval *time_stamp;
 	uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
 	uint32_t frame_id = vfe_dev->axi_data.
 		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
 
 	if (buf && ts) {
+		if (vfe_dev->vt_enable) {
+			time_stamp = &ts->vt_time;
+		} else {
+			time_stamp = &ts->buf_time;
+		}
 		if (stream_info->buf_divert) {
 			rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
 				buf->bufq_handle, buf->buf_idx,
-				&ts->buf_time, frame_id);
+				time_stamp, frame_id);
 			/* Buf divert return value represent whether the buf
 			 * can be diverted. A positive return value means
 			 * other ISP hardware is still processing the frame.
@@ -800,7 +815,7 @@
 				buf_event.input_intf =
 					SRC_TO_INTF(stream_info->stream_src);
 				buf_event.frame_id = frame_id;
-				buf_event.timestamp = ts->buf_time;
+				buf_event.timestamp = *time_stamp;
 				buf_event.u.buf_done.session_id =
 					stream_info->session_id;
 				buf_event.u.buf_done.stream_id =
@@ -817,7 +832,7 @@
 		} else {
 			vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
 				buf->bufq_handle, buf->buf_idx,
-				&ts->buf_time, frame_id,
+				time_stamp, frame_id,
 				stream_info->runtime_output_format);
 		}
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index b024569..5f36a4a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -193,6 +193,32 @@
 	do_gettimeofday(&(time_stamp->event_time));
 }
 
+static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev,
+	struct msm_isp_timestamp *time_stamp)
+{
+	uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
+	uint32_t avtimer_msw_2nd = 0;
+	uint8_t iter = 0;
+	if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) {
+		pr_err("%s: ioremap failed\n", __func__);
+		return;
+	}
+	do {
+		avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw);
+		avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw);
+		avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw);
+	} while ((avtimer_msw_1st != avtimer_msw_2nd)
+		&& (iter++ < AVTIMER_ITERATION_CTR));
+	/*Just return if the MSW TimeStamps don't converge after
+	a few iterations Application needs to handle the zero TS values*/
+	if (iter >= AVTIMER_ITERATION_CTR) {
+		pr_err("%s: AVTimer MSW TS did not converge !!!\n", __func__);
+		return;
+	}
+	time_stamp->vt_time.tv_sec = avtimer_msw_1st;
+	time_stamp->vt_time.tv_usec = avtimer_lsw;
+}
+
 int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
 	struct v4l2_event_subscription *sub)
 {
@@ -885,6 +911,8 @@
 	queue_cmd->vfeInterruptStatus0 = irq_status0;
 	queue_cmd->vfeInterruptStatus1 = irq_status1;
 	msm_isp_get_timestamp(&queue_cmd->ts);
+	if (vfe_dev->vt_enable)
+		msm_isp_get_vt_tstamp(vfe_dev, &queue_cmd->ts);
 	queue_cmd->cmd_used = 1;
 	vfe_dev->taskletq_idx =
 		(vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE;
@@ -998,6 +1026,9 @@
 	vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
 	vfe_dev->vfe_open_cnt++;
 	vfe_dev->taskletq_idx = 0;
+	vfe_dev->vt_enable = 0;
+	vfe_dev->p_avtimer_lsw = NULL;
+	vfe_dev->p_avtimer_msw = NULL;
 	mutex_unlock(&vfe_dev->core_mutex);
 	mutex_unlock(&vfe_dev->realtime_mutex);
 	return 0;
@@ -1024,6 +1055,14 @@
 	vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
 	vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
 	vfe_dev->vfe_open_cnt--;
+	if (vfe_dev->vt_enable) {
+		iounmap(vfe_dev->p_avtimer_lsw);
+		iounmap(vfe_dev->p_avtimer_msw);
+	#ifdef CONFIG_MSM_AVTIMER
+		avcs_core_disable_power_collapse(0);
+	#endif
+		vfe_dev->vt_enable = 0;
+	}
 	mutex_unlock(&vfe_dev->core_mutex);
 	mutex_unlock(&vfe_dev->realtime_mutex);
 	return 0;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 2b963a4..89016ec 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -72,6 +72,18 @@
 	{"csi0_clk", NO_SET_RATE},
 	{"csi0_pix_clk", NO_SET_RATE},
 	{"csi0_rdi_clk", NO_SET_RATE},
+	{"csi1_src_clk", INIT_RATE},
+	{"csi1_clk", NO_SET_RATE},
+	{"csi1_pix_clk", NO_SET_RATE},
+	{"csi1_rdi_clk", NO_SET_RATE},
+	{"csi2_src_clk", INIT_RATE},
+	{"csi2_clk", NO_SET_RATE},
+	{"csi2_pix_clk", NO_SET_RATE},
+	{"csi2_rdi_clk", NO_SET_RATE},
+	{"csi3_src_clk", INIT_RATE},
+	{"csi3_clk", NO_SET_RATE},
+	{"csi3_pix_clk", NO_SET_RATE},
+	{"csi3_rdi_clk", NO_SET_RATE},
 	{"vfe0_clk_src", INIT_RATE},
 	{"camss_vfe_vfe0_clk", NO_SET_RATE},
 	{"camss_csi_vfe0_clk", NO_SET_RATE},
@@ -110,6 +122,9 @@
 	CDBG("%s: VFE0 done\n", __func__);
 	if (timeout <= 0) {
 		pr_err("%s: VFE0 reset wait timeout\n", __func__);
+		msm_cam_clk_enable(&ispif->pdev->dev,
+			ispif_8974_reset_clk_info, reset_clk,
+			ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
 		return -ETIMEDOUT;
 	}
 
@@ -120,6 +135,9 @@
 		CDBG("%s: VFE1 done\n", __func__);
 		if (timeout <= 0) {
 			pr_err("%s: VFE1 reset wait timeout\n", __func__);
+			msm_cam_clk_enable(&ispif->pdev->dev,
+				ispif_8974_reset_clk_info, reset_clk,
+				ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
 			return -ETIMEDOUT;
 		}
 	}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index c1f48f5..8b8d23b 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -27,6 +27,7 @@
 #include <linux/timer.h>
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
+#include <mach/clk.h>
 #include <mach/iommu_domains.h>
 #include <mach/iommu.h>
 #include <mach/vreg.h>
@@ -48,6 +49,7 @@
 #define CONFIG_MSM_CPP_DBG 0
 
 #define CPP_CMD_TIMEOUT_MS 300
+#define MSM_MICRO_IFACE_CLK_IDX 7
 
 struct msm_cpp_timer_data_t {
 	struct cpp_device *cpp_dev;
@@ -646,6 +648,38 @@
 		}
 	}
 
+	cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX] =
+		clk_get(&cpp_dev->pdev->dev,
+		cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name);
+	if (IS_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX])) {
+		pr_err("%s get failed\n",
+			cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name);
+		rc = PTR_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]);
+		goto remap_failed;
+	}
+
+	rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX],
+		CLK_RESET_ASSERT);
+	if (rc) {
+		pr_err("%s:micro_iface_clk assert failed\n", __func__);
+		clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]);
+		goto remap_failed;
+	}
+
+	usleep_range(10000, 12000);
+
+	rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX],
+		CLK_RESET_DEASSERT);
+	  if (rc) {
+		pr_err("%s:micro_iface_clk assert failed\n", __func__);
+		clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]);
+		goto remap_failed;
+	}
+
+	usleep_range(1000, 1200);
+
+	clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]);
+
 	rc = msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
 			cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 1);
 	if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index bd1b10b..280a9a0 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -7,7 +7,9 @@
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
 obj-$(CONFIG_IMX135) += imx135.o
+obj-$(CONFIG_IMX134) += imx134.o
 obj-$(CONFIG_OV8825) += ov8825.o
+obj-$(CONFIG_OV8865) += ov8865.o
 obj-$(CONFIG_s5k4e1) += s5k4e1.o
 obj-$(CONFIG_OV12830) += ov12830.o
 obj-$(CONFIG_OV2720) += ov2720.o
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 32d74ba..16a1616 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
@@ -41,6 +41,7 @@
 	struct msm_actuator_move_params_t *move_params)
 {
 	int32_t rc = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
 	if (a_ctrl->curr_step_pos != 0) {
@@ -49,10 +50,12 @@
 			a_ctrl->initial_code, 0, 0);
 		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
 			a_ctrl->initial_code, 0, 0);
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
 		rc = a_ctrl->i2c_client.i2c_func_tbl->
 			i2c_write_table_w_microdelay(
-			&a_ctrl->i2c_client, a_ctrl->i2c_reg_tbl,
-			a_ctrl->i2c_tbl_index, a_ctrl->i2c_data_type);
+			&a_ctrl->i2c_client, &reg_setting);
 		if (rc < 0) {
 			pr_err("%s: i2c write error:%d\n",
 				__func__, rc);
@@ -73,7 +76,7 @@
 	uint16_t i2c_byte1 = 0, i2c_byte2 = 0;
 	uint16_t value = 0;
 	uint32_t size = a_ctrl->reg_tbl_size, i = 0;
-	struct msm_camera_i2c_reg_tbl *i2c_tbl = a_ctrl->i2c_reg_tbl;
+	struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl;
 	CDBG("Enter\n");
 	for (i = 0; i < size; i++) {
 		if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
@@ -195,6 +198,7 @@
 	int32_t dest_step_position = move_params->dest_step_pos;
 	int32_t rc = 0;
 	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
 	if (num_steps == 0)
@@ -206,10 +210,11 @@
 		a_ctrl->region_params[0].code_per_step),
 		move_params->ringing_params[0].hw_params, 0);
 
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
 	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
-		&a_ctrl->i2c_client,
-		a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
-		a_ctrl->i2c_data_type);
+		&a_ctrl->i2c_client, &reg_setting);
 	if (rc < 0) {
 		pr_err("i2c write error:%d\n", rc);
 		return rc;
@@ -233,6 +238,7 @@
 	uint16_t curr_lens_pos = 0;
 	int dir = move_params->dir;
 	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
 
 	CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
 
@@ -280,10 +286,11 @@
 		a_ctrl->curr_step_pos = target_step_pos;
 	}
 
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
 	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
-		&a_ctrl->i2c_client,
-		a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
-		a_ctrl->i2c_data_type);
+		&a_ctrl->i2c_client, &reg_setting);
 	if (rc < 0) {
 		pr_err("i2c write error:%d\n", rc);
 		return rc;
@@ -439,7 +446,7 @@
 	kfree(a_ctrl->i2c_reg_tbl);
 
 	a_ctrl->i2c_reg_tbl =
-		kmalloc(sizeof(struct msm_camera_i2c_reg_tbl) *
+		kmalloc(sizeof(struct msm_camera_i2c_reg_array) *
 		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
 	if (!a_ctrl->i2c_reg_tbl) {
 		pr_err("kmalloc fail\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
index c4a4137..809c9cf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -77,7 +77,7 @@
 	uint32_t total_steps;
 	uint16_t pwd_step;
 	uint16_t initial_code;
-	struct msm_camera_i2c_reg_tbl *i2c_reg_tbl;
+	struct msm_camera_i2c_reg_array *i2c_reg_tbl;
 	uint16_t i2c_tbl_index;
 	enum cci_i2c_master_t cci_master;
 	uint32_t subdev_id;
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 3320537..968dcd7 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
@@ -26,6 +26,8 @@
 #define V4L2_IDENT_CCI 50005
 #define CCI_I2C_QUEUE_0_SIZE 64
 #define CCI_I2C_QUEUE_1_SIZE 16
+#define CYCLES_PER_MICRO_SEC 4915
+#define CCI_MAX_DELAY 10000
 
 #define CCI_TIMEOUT msecs_to_jiffies(100)
 
@@ -178,13 +180,13 @@
 {
 	uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
 	int32_t rc = 0;
-	uint32_t cmd = 0;
+	uint32_t cmd = 0, delay = 0;
 	uint8_t data[10];
 	uint16_t reg_addr = 0;
-	struct msm_camera_cci_i2c_write_cfg *i2c_msg =
+	struct msm_camera_i2c_reg_setting *i2c_msg =
 		&c_ctrl->cfg.cci_i2c_write_cfg;
 	uint16_t cmd_size = i2c_msg->size;
-	struct msm_camera_i2c_reg_conf *i2c_cmd = i2c_msg->reg_conf_tbl;
+	struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
 	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
 
 	if (i2c_cmd == NULL) {
@@ -213,6 +215,7 @@
 	while (cmd_size) {
 		CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
 			cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
+		delay = i2c_cmd->delay;
 		data[i++] = CCI_I2C_WRITE_CMD;
 		if (i2c_cmd->reg_addr)
 			reg_addr = i2c_cmd->reg_addr;
@@ -257,6 +260,17 @@
 				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
 				master * 0x200 + queue * 0x100);
 		}
+		if ((delay > 0) && (delay < CCI_MAX_DELAY)) {
+			cmd = (uint32_t)((delay * CYCLES_PER_MICRO_SEC) /
+				0x100);
+			cmd <<= 4;
+			cmd |= CCI_I2C_WAIT_CMD;
+			CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
+				__func__, cmd);
+			msm_camera_io_w(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+		}
 		i = 0;
 	}
 	return rc;
@@ -865,10 +879,7 @@
 		rc = msm_cci_config(sd, arg);
 		break;
 	case MSM_SD_SHUTDOWN: {
-		struct msm_camera_cci_ctrl ctrl_cmd;
-		ctrl_cmd.cmd = MSM_CCI_RELEASE;
-		rc = msm_cci_config(sd, &ctrl_cmd);
-		break;
+		return rc;
 	}
 	default:
 		rc = -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index 16edaae..6067f26 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -64,13 +64,6 @@
 	uint16_t i2c_queue;
 };
 
-struct msm_camera_cci_i2c_write_cfg {
-	struct msm_camera_i2c_reg_conf *reg_conf_tbl;
-	enum msm_camera_i2c_reg_addr_type addr_type;
-	enum msm_camera_i2c_data_type data_type;
-	uint16_t size;
-};
-
 struct msm_camera_cci_i2c_read_cfg {
 	uint16_t addr;
 	enum msm_camera_i2c_reg_addr_type addr_type;
@@ -90,7 +83,7 @@
 	struct msm_camera_cci_client *cci_info;
 	enum msm_cci_cmd_type cmd;
 	union {
-		struct msm_camera_cci_i2c_write_cfg cci_i2c_write_cfg;
+		struct msm_camera_i2c_reg_setting cci_i2c_write_cfg;
 		struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
 		struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
 		struct msm_camera_cci_gpio_cfg gpio_cfg;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index 835230e..a10d60e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -33,7 +33,7 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 20,
+		.delay = 0,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
@@ -63,13 +63,13 @@
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 20,
+		.delay = 0,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
@@ -81,7 +81,7 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx134.c b/drivers/media/platform/msm/camera_v2/sensor/imx134.c
new file mode 100644
index 0000000..17a5088
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx134.c
@@ -0,0 +1,174 @@
+/* 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 "msm_sensor.h"
+#define IMX134_SENSOR_NAME "imx134"
+DEFINE_MSM_MUTEX(imx134_mut);
+
+static struct msm_sensor_ctrl_t imx134_s_ctrl;
+
+static struct msm_sensor_power_setting imx134_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 30,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 30,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info imx134_subdev_info[] = {
+	{
+		.code = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt = 1,
+		.order = 0,
+	},
+};
+
+static const struct i2c_device_id imx134_i2c_id[] = {
+	{IMX134_SENSOR_NAME, (kernel_ulong_t)&imx134_s_ctrl},
+	{ }
+};
+
+static int32_t msm_imx134_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &imx134_s_ctrl);
+}
+
+static struct i2c_driver imx134_i2c_driver = {
+	.id_table = imx134_i2c_id,
+	.probe  = msm_imx134_i2c_probe,
+	.driver = {
+		.name = IMX134_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client imx134_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id imx134_dt_match[] = {
+	{.compatible = "sne,imx134", .data = &imx134_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, imx134_dt_match);
+
+static struct platform_driver imx134_platform_driver = {
+	.driver = {
+		.name = "sne,imx134",
+		.owner = THIS_MODULE,
+		.of_match_table = imx134_dt_match,
+	},
+};
+
+static int32_t imx134_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(imx134_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init imx134_init_module(void)
+{
+	int32_t rc = 0;
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&imx134_platform_driver,
+		imx134_platform_probe);
+	if (!rc)
+		return rc;
+	pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&imx134_i2c_driver);
+}
+
+static void __exit imx134_exit_module(void)
+{
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (imx134_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&imx134_s_ctrl);
+		platform_driver_unregister(&imx134_platform_driver);
+	} else {
+		i2c_del_driver(&imx134_i2c_driver);
+	}
+	return;
+}
+
+static struct msm_sensor_ctrl_t imx134_s_ctrl = {
+	.sensor_i2c_client = &imx134_sensor_i2c_client,
+	.power_setting_array.power_setting = imx134_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(imx134_power_setting),
+	.msm_sensor_mutex = &imx134_mut,
+	.sensor_v4l2_subdev_info = imx134_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx134_subdev_info),
+};
+
+module_init(imx134_init_module);
+module_exit(imx134_exit_module);
+MODULE_DESCRIPTION("imx134");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 3792247..8d9274b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -108,7 +108,7 @@
 {
 	int32_t rc = -EFAULT;
 	struct msm_camera_cci_ctrl cci_ctrl;
-	struct msm_camera_i2c_reg_conf reg_conf_tbl;
+	struct msm_camera_i2c_reg_array reg_conf_tbl;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
@@ -122,7 +122,7 @@
 	reg_conf_tbl.reg_data = data;
 	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
 	cci_ctrl.cci_info = client->cci_client;
-	cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = &reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = &reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
@@ -142,7 +142,7 @@
 	int32_t rc = -EFAULT;
 	uint8_t i = 0;
 	struct msm_camera_cci_ctrl cci_ctrl;
-	struct msm_camera_i2c_reg_conf reg_conf_tbl[num_byte];
+	struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte];
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
@@ -152,13 +152,15 @@
 	S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
 			  __func__, addr, num_byte);
 	memset(reg_conf_tbl, 0,
-		num_byte * sizeof(struct msm_camera_i2c_reg_conf));
+		num_byte * sizeof(struct msm_camera_i2c_reg_array));
 	reg_conf_tbl[0].reg_addr = addr;
-	for (i = 0; i < num_byte; i++)
+	for (i = 0; i < num_byte; i++) {
 		reg_conf_tbl[i].reg_data = data[i];
+		reg_conf_tbl[i].delay = 0;
+	}
 	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
 	cci_ctrl.cci_info = client->cci_client;
-	cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA;
 	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte;
@@ -173,10 +175,8 @@
 	struct msm_camera_i2c_client *client,
 	struct msm_camera_i2c_reg_setting *write_setting)
 {
-	int i;
 	int32_t rc = -EFAULT;
-	struct msm_camera_i2c_reg_array *reg_setting;
-	uint16_t client_addr_type;
+	struct msm_camera_cci_ctrl cci_ctrl;
 
 	if (!client || !write_setting)
 		return rc;
@@ -187,24 +187,26 @@
 		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	reg_setting = write_setting->reg_setting;
-	client_addr_type = client->addr_type;
-	client->addr_type = write_setting->addr_type;
-
-	for (i = 0; i < write_setting->size; i++) {
-		rc = msm_camera_cci_i2c_write(client, reg_setting->reg_addr,
-			reg_setting->reg_data, write_setting->data_type);
-		if (rc < 0)
-			return rc;
-		reg_setting++;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
 	}
+	rc = cci_ctrl.status;
 	if (write_setting->delay > 20)
 		msleep(write_setting->delay);
 	else if (write_setting->delay)
 		usleep_range(write_setting->delay * 1000, (write_setting->delay
 			* 1000) + 1000);
 
-	client->addr_type = client_addr_type;
 	return rc;
 }
 
@@ -250,30 +252,34 @@
 
 int32_t msm_camera_cci_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type)
+	struct msm_camera_i2c_reg_setting *write_setting)
 {
-	int i;
 	int32_t rc = -EFAULT;
+	struct msm_camera_cci_ctrl cci_ctrl;
 
-	if (!client || !reg_tbl)
+	if (!client || !write_setting)
 		return rc;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
-		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
-		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	for (i = 0; i < size; i++) {
-		rc = msm_camera_cci_i2c_write(client, reg_tbl->reg_addr,
-			reg_tbl->reg_data, data_type);
-		if (rc < 0)
-			return rc;
-		if (reg_tbl->delay)
-			usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
-		reg_tbl++;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
 	}
+	rc = cci_ctrl.status;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
index 389e9d9..763c131 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -25,12 +25,6 @@
 	enum msm_camera_i2c_reg_addr_type addr_type;
 };
 
-struct msm_camera_i2c_reg_tbl {
-	uint16_t reg_addr;
-	uint16_t reg_data;
-	uint16_t delay;
-};
-
 struct msm_camera_i2c_fn_t {
 	int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *,
 		enum msm_camera_i2c_data_type);
@@ -46,8 +40,7 @@
 		struct msm_camera_i2c_seq_reg_setting *);
 	int32_t (*i2c_write_table_w_microdelay)
 		(struct msm_camera_i2c_client *,
-		struct msm_camera_i2c_reg_tbl *, uint16_t,
-		enum msm_camera_i2c_data_type);
+		struct msm_camera_i2c_reg_setting *);
 	int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t);
 	int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client,
 		struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
@@ -81,8 +74,7 @@
 
 int32_t msm_camera_cci_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type);
+	struct msm_camera_i2c_reg_setting *write_setting);
 
 int32_t msm_camera_cci_i2c_write_conf_tbl(
 	struct msm_camera_i2c_client *client,
@@ -118,8 +110,7 @@
 
 int32_t msm_camera_qup_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type);
+	struct msm_camera_i2c_reg_setting *write_setting);
 
 int32_t msm_camera_qup_i2c_write_conf_tbl(
 	struct msm_camera_i2c_client *client,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
index 60d1509..d5b89b7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -308,29 +308,31 @@
 
 int32_t msm_camera_qup_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type)
+	struct msm_camera_i2c_reg_setting *write_setting)
 {
 	int i;
 	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting = NULL;
 
-	if (!client || !reg_tbl)
+	if (!client || !write_setting)
 		return rc;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
-		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
-		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	for (i = 0; i < size; i++) {
-		rc = msm_camera_qup_i2c_write(client, reg_tbl->reg_addr,
-			reg_tbl->reg_data, data_type);
+	reg_setting = write_setting->reg_setting;
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
 		if (rc < 0)
 			break;
-		if (reg_tbl->delay)
-			usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
-		reg_tbl++;
+		if (reg_setting->delay)
+			usleep_range(reg_setting->delay,
+				reg_setting->delay + 1000);
+		reg_setting++;
 	}
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index ddc168a..0083378 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1272,9 +1272,10 @@
 	case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
 		return msm_sensor_get_af_status(s_ctrl, argp);
 	case VIDIOC_MSM_SENSOR_RELEASE:
-	case MSM_SD_SHUTDOWN:
 		msm_sensor_stop_stream(s_ctrl);
 		return 0;
+	case MSM_SD_SHUTDOWN:
+		return 0;
 	default:
 		return -ENOIOCTLCMD;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
index 417c7ab..9922468 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
@@ -126,7 +126,7 @@
 
 static const struct of_device_id ov5648_dt_match[] = {
 	{
-		.compatible = "qcom,ov5648",
+		.compatible = "ovti,ov5648",
 		.data = &ov5648_s_ctrl
 	},
 	{}
@@ -136,7 +136,7 @@
 
 static struct platform_driver ov5648_platform_driver = {
 	.driver = {
-		.name = "qcom,ov5648",
+		.name = "ovti,ov5648",
 		.owner = THIS_MODULE,
 		.of_match_table = ov5648_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8865.c b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
new file mode 100644
index 0000000..6d788f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
@@ -0,0 +1,185 @@
+/* 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 "msm_sensor.h"
+#define OV8865_SENSOR_NAME "ov8865"
+DEFINE_MSM_MUTEX(ov8865_mut);
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl;
+
+static struct msm_sensor_power_setting ov8865_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info ov8865_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static const struct i2c_device_id ov8865_i2c_id[] = {
+	{OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl},
+	{ }
+};
+
+static int32_t msm_ov8865_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl);
+}
+
+static struct i2c_driver ov8865_i2c_driver = {
+	.id_table = ov8865_i2c_id,
+	.probe  = msm_ov8865_i2c_probe,
+	.driver = {
+		.name = OV8865_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov8865_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov8865_dt_match[] = {
+	{.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, ov8865_dt_match);
+
+static struct platform_driver ov8865_platform_driver = {
+	.driver = {
+		.name = "ovti,ov8865",
+		.owner = THIS_MODULE,
+		.of_match_table = ov8865_dt_match,
+	},
+};
+
+static int32_t ov8865_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(ov8865_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init ov8865_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&ov8865_platform_driver,
+		ov8865_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&ov8865_i2c_driver);
+}
+
+static void __exit ov8865_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (ov8865_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&ov8865_s_ctrl);
+		platform_driver_unregister(&ov8865_platform_driver);
+	} else
+		i2c_del_driver(&ov8865_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl = {
+	.sensor_i2c_client = &ov8865_sensor_i2c_client,
+	.power_setting_array.power_setting = ov8865_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(ov8865_power_setting),
+	.msm_sensor_mutex = &ov8865_mut,
+	.sensor_v4l2_subdev_info = ov8865_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info),
+};
+
+module_init(ov8865_init_module);
+module_exit(ov8865_exit_module);
+MODULE_DESCRIPTION("ov8865");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 1dba2b6..e982feb 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -371,6 +371,9 @@
 	case HAL_BUFFER_MODE_RING:
 		buf_mode = HFI_BUFFER_MODE_RING;
 		break;
+	case HAL_BUFFER_MODE_DYNAMIC:
+		buf_mode = HFI_BUFFER_MODE_DYNAMIC;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid buffer mode :0x%x\n",
 				hal_buf_mode);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 2b6118a..2bd038d 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -163,6 +163,38 @@
 	callback(VIDC_EVENT_CHANGE, &cmd_done);
 }
 
+static void hfi_process_evt_release_buffer_ref(
+		msm_vidc_callback callback, u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	struct msm_vidc_cb_event event_notify = {0};
+
+	struct hfi_msg_release_buffer_ref_event_packet *data;
+
+	dprintk(VIDC_DBG, "RECEIVED:EVENT_NOTIFY - release_buffer_reference");
+	if (sizeof(struct hfi_msg_event_notify_packet)
+		> pkt->size) {
+		dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
+		return;
+	}
+
+	data = (struct hfi_msg_release_buffer_ref_event_packet *)
+				pkt->rg_ext_event_data;
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+		session_id;
+	cmd_done.status = VIDC_ERR_NONE;
+	cmd_done.size = sizeof(struct msm_vidc_cb_event);
+
+	event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
+	event_notify.packet_buffer = data->packet_buffer;
+	event_notify.exra_data_buffer = data->exra_data_buffer;
+	cmd_done.data = &event_notify;
+	callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
 static void hfi_process_sys_error(
 		msm_vidc_callback callback, u32 device_id)
 {
@@ -180,7 +212,19 @@
 	cmd_done.device_id = device_id;
 	cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
 		session_id;
-	callback(SESSION_ERROR, &cmd_done);
+	dprintk(VIDC_INFO, "Received : SESSION_ERROR with event id : %d\n",
+		pkt->event_data1);
+	switch (pkt->event_data1) {
+	case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
+	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
+	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+		dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
+		break;
+	default:
+		dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n");
+		callback(SESSION_ERROR, &cmd_done);
+		break;
+	}
 }
 static void hfi_process_event_notify(
 		msm_vidc_callback callback, u32 device_id,
@@ -204,7 +248,7 @@
 		hfi_process_sys_error(callback, device_id);
 		break;
 	case HFI_EVENT_SESSION_ERROR:
-		dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR");
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
 		if (!validate_session_pkt(sessions, sess, session_lock))
 			hfi_process_session_error(callback, device_id, pkt);
 		break;
@@ -217,6 +261,10 @@
 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
 		break;
+	case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
+		dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE\n");
+		hfi_process_evt_release_buffer_ref(callback, device_id, pkt);
+		break;
 	default:
 		dprintk(VIDC_WARN, "hal_process_event_notify:unkown_event_id");
 		break;
@@ -532,6 +580,39 @@
 			num_properties--;
 			break;
 		}
+		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
+		{
+			struct hfi_buffer_alloc_mode_supported *prop =
+				(struct hfi_buffer_alloc_mode_supported *)
+				(data_ptr + next_offset);
+			int i;
+			if (prop->buffer_type == HFI_BUFFER_OUTPUT ||
+				prop->buffer_type == HFI_BUFFER_OUTPUT2) {
+				sess_init_done->alloc_mode_out = 0;
+				for (i = 0; i < prop->num_entries; i++) {
+					switch (prop->rg_data[i]) {
+					case HFI_BUFFER_MODE_STATIC:
+						sess_init_done->alloc_mode_out
+						|= HAL_BUFFER_MODE_STATIC;
+						break;
+					case HFI_BUFFER_MODE_DYNAMIC:
+						sess_init_done->alloc_mode_out
+						|= HAL_BUFFER_MODE_DYNAMIC;
+						break;
+					}
+					if (i >= 32) {
+						dprintk(VIDC_ERR,
+						"%s - num_entries: %d from f/w seems suspect\n",
+						__func__, prop->num_entries);
+						break;
+					}
+				}
+			}
+			next_offset += sizeof(*prop) -
+				sizeof(u32) + prop->num_entries * sizeof(u32);
+			num_properties--;
+			break;
+		}
 		default:
 			dprintk(VIDC_DBG,
 				"%s default case - 0x%x", __func__, prop_id);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index e335ff0..81afd5c 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -27,7 +27,6 @@
 #include "msm_vidc_internal.h"
 #include "msm_vidc_debug.h"
 #include "vidc_hfi_api.h"
-#include "msm_smem.h"
 #include "vidc_hfi_api.h"
 #include "msm_vidc_resources.h"
 #include "msm_vidc_res_parse.h"
@@ -38,258 +37,44 @@
 
 uint32_t msm_vidc_pwr_collapse_delay = 2000;
 
-struct buffer_info {
-	struct list_head list;
-	int type;
-	int num_planes;
-	int fd[VIDEO_MAX_PLANES];
-	int buff_off[VIDEO_MAX_PLANES];
-	int size[VIDEO_MAX_PLANES];
-	u32 uvaddr[VIDEO_MAX_PLANES];
-	u32 device_addr[VIDEO_MAX_PLANES];
-	struct msm_smem *handle[VIDEO_MAX_PLANES];
-};
-
-struct msm_v4l2_vid_inst {
-	struct msm_vidc_inst *vidc_inst;
-	void *mem_client;
-	struct list_head registered_bufs;
-};
-
 static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
 {
 	return container_of(filp->private_data,
 					struct msm_vidc_inst, event_handler);
 }
 
-static inline struct msm_v4l2_vid_inst *get_v4l2_inst(struct file *filp,
-			void *fh)
-{
-	struct msm_vidc_inst *vidc_inst;
-	vidc_inst = container_of(filp->private_data,
-			struct msm_vidc_inst, event_handler);
-	return (struct msm_v4l2_vid_inst *)vidc_inst->priv;
-}
-
-struct buffer_info *get_registered_buf(struct list_head *list,
-				int fd, u32 buff_off, u32 size, int *plane)
-{
-	struct buffer_info *temp;
-	struct buffer_info *ret = NULL;
-	int i;
-	if (!list || fd < 0 || !plane) {
-		dprintk(VIDC_ERR, "Invalid input\n");
-		goto err_invalid_input;
-	}
-	*plane = 0;
-	if (!list_empty(list)) {
-		list_for_each_entry(temp, list, list) {
-			for (i = 0; (i < temp->num_planes)
-				&& (i < VIDEO_MAX_PLANES); i++) {
-				if (temp && temp->fd[i] == fd &&
-						(CONTAINS(temp->buff_off[i],
-						temp->size[i], buff_off)
-						 || CONTAINS(buff_off,
-						 size, temp->buff_off[i])
-						 || OVERLAPS(buff_off, size,
-						 temp->buff_off[i],
-						 temp->size[i]))) {
-					dprintk(VIDC_DBG,
-							"This memory region is already mapped\n");
-					ret = temp;
-					*plane = i;
-					break;
-				}
-			}
-			if (ret)
-				break;
-		}
-	}
-err_invalid_input:
-	return ret;
-}
-
-struct buffer_info *get_same_fd_buffer(struct list_head *list,
-		int fd, int *plane)
-{
-	struct buffer_info *temp;
-	struct buffer_info *ret = NULL;
-	int i;
-	if (!list || fd < 0 || !plane) {
-		dprintk(VIDC_ERR, "Invalid input\n");
-		goto err_invalid_input;
-	}
-	*plane = 0;
-	if (!list_empty(list)) {
-		list_for_each_entry(temp, list, list) {
-			for (i = 0; (i < temp->num_planes)
-				&& (i < VIDEO_MAX_PLANES); i++) {
-				if (temp && temp->fd[i] == fd)  {
-					dprintk(VIDC_INFO,
-					"Found same fd buffer\n");
-					ret = temp;
-					*plane = i;
-					break;
-				}
-			}
-			if (ret)
-				break;
-		}
-	}
-err_invalid_input:
-	return ret;
-}
-
-static struct buffer_info *device_to_uvaddr(
-	struct list_head *list, u32 device_addr)
-{
-	struct buffer_info *temp = NULL;
-	int found = 0;
-	int i;
-	if (!list || !device_addr) {
-		dprintk(VIDC_ERR, "Invalid input\n");
-		goto err_invalid_input;
-	}
-	if (!list_empty(list)) {
-		list_for_each_entry(temp, list, list) {
-			for (i = 0; (i < temp->num_planes)
-				&& (i < VIDEO_MAX_PLANES); i++) {
-				if (temp && temp->device_addr[i]
-						== device_addr)  {
-					dprintk(VIDC_INFO,
-					"Found same fd buffer\n");
-					found = 1;
-					break;
-				}
-			}
-			if (found)
-				break;
-		}
-	}
-err_invalid_input:
-	return temp;
-}
-
 static int msm_v4l2_open(struct file *filp)
 {
-	int rc = 0;
 	struct video_device *vdev = video_devdata(filp);
 	struct msm_video_device *vid_dev =
 		container_of(vdev, struct msm_video_device, vdev);
 	struct msm_vidc_core *core = video_drvdata(filp);
-	struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
-						GFP_KERNEL);
-	if (!v4l2_inst) {
-		dprintk(VIDC_ERR,
-			"Failed to allocate memory for this instance\n");
-		rc = -ENOMEM;
-		goto fail_nomem;
-	}
-	v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION, &core->resources);
-	if (!v4l2_inst->mem_client) {
-		dprintk(VIDC_ERR, "Failed to create memory client\n");
-		rc = -ENOMEM;
-		goto fail_mem_client;
-	}
+	struct msm_vidc_inst *vidc_inst;
 
-	v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
-	if (!v4l2_inst->vidc_inst) {
+	vidc_inst = msm_vidc_open(core->id, vid_dev->type);
+	if (!vidc_inst) {
 		dprintk(VIDC_ERR,
 		"Failed to create video instance, core: %d, type = %d\n",
 		core->id, vid_dev->type);
-		rc = -ENOMEM;
-		goto fail_open;
+		return -ENOMEM;
 	}
-	INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
-	v4l2_inst->vidc_inst->priv = v4l2_inst;
 	clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
-	filp->private_data = &(v4l2_inst->vidc_inst->event_handler);
-	return rc;
-fail_open:
-	msm_smem_delete_client(v4l2_inst->mem_client);
-fail_mem_client:
-	kfree(v4l2_inst);
-fail_nomem:
-	return rc;
-}
-static int msm_v4l2_release_buffers(struct msm_v4l2_vid_inst *v4l2_inst,
-				int buffer_type)
-{
-	struct list_head *ptr, *next;
-	struct buffer_info *bi;
-	struct v4l2_buffer buffer_info;
-	struct v4l2_plane plane[VIDEO_MAX_PLANES];
-	int rc = 0;
-	int i;
-	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
-		bi = list_entry(ptr, struct buffer_info, list);
-		if (bi->type == buffer_type) {
-			buffer_info.type = bi->type;
-			for (i = 0; (i < bi->num_planes)
-				&& (i < VIDEO_MAX_PLANES); i++) {
-				plane[i].reserved[0] = bi->fd[i];
-				plane[i].reserved[1] = bi->buff_off[i];
-				plane[i].length = bi->size[i];
-				plane[i].m.userptr = bi->device_addr[i];
-				buffer_info.m.planes = plane;
-				dprintk(VIDC_DBG,
-					"Releasing buffer: %d, %d, %d\n",
-					buffer_info.m.planes[i].reserved[0],
-					buffer_info.m.planes[i].reserved[1],
-					buffer_info.m.planes[i].length);
-			}
-			buffer_info.length = bi->num_planes;
-			rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
-					&buffer_info);
-			if (rc)
-				dprintk(VIDC_ERR,
-					"Failed Release buffer: %d, %d, %d\n",
-					buffer_info.m.planes[0].reserved[0],
-					buffer_info.m.planes[0].reserved[1],
-					buffer_info.m.planes[0].length);
-			list_del(&bi->list);
-			for (i = 0; i < bi->num_planes; i++) {
-				if (bi->handle[i])
-					msm_smem_free(v4l2_inst->mem_client,
-							bi->handle[i]);
-			}
-			kfree(bi);
-		}
-	}
-	return rc;
+	filp->private_data = &(vidc_inst->event_handler);
+	return 0;
 }
 
 static int msm_v4l2_close(struct file *filp)
 {
 	int rc = 0;
-	struct list_head *ptr, *next;
-	struct buffer_info *bi;
 	struct msm_vidc_inst *vidc_inst;
-	struct msm_v4l2_vid_inst *v4l2_inst;
-	int i;
 	vidc_inst = get_vidc_inst(filp, NULL);
-	v4l2_inst = get_v4l2_inst(filp, NULL);
-	rc = msm_v4l2_release_buffers(v4l2_inst,
+	rc = msm_vidc_release_buffers(vidc_inst,
 			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed in %s for release output buffers\n", __func__);
-	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
-		bi = list_entry(ptr, struct buffer_info, list);
-		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-			list_del(&bi->list);
-			for (i = 0; (i < bi->num_planes)
-				&& (i < VIDEO_MAX_PLANES); i++) {
-				if (bi->handle[i])
-					msm_smem_free(v4l2_inst->mem_client,
-							bi->handle[i]);
-			}
-			kfree(bi);
-		}
-	}
-	msm_smem_delete_client(v4l2_inst->mem_client);
+
 	rc = msm_vidc_close(vidc_inst);
-	kfree(v4l2_inst);
 	return rc;
 }
 
@@ -339,11 +124,9 @@
 				struct v4l2_requestbuffers *b)
 {
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
-	struct msm_v4l2_vid_inst *v4l2_inst;
 	int rc = 0;
-	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (b->count == 0)
-		rc = msm_v4l2_release_buffers(v4l2_inst, b->type);
+		rc = msm_vidc_release_buffers(vidc_inst, b->type);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed in %s for release output buffers\n", __func__);
@@ -353,234 +136,19 @@
 int msm_v4l2_prepare_buf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_smem *handle = NULL;
-	struct buffer_info *binfo;
-	struct buffer_info *temp;
-	struct msm_vidc_inst *vidc_inst;
-	struct msm_v4l2_vid_inst *v4l2_inst;
-	int plane = 0;
-	int i, rc = 0;
-	struct hfi_device *hdev;
-	enum hal_buffer buffer_type;
-
-	vidc_inst = get_vidc_inst(file, fh);
-	v4l2_inst = get_v4l2_inst(file, fh);
-	if (!v4l2_inst || !vidc_inst || !vidc_inst->core
-		|| !vidc_inst->core->device) {
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	hdev = vidc_inst->core->device;
-
-	if (!v4l2_inst->mem_client) {
-		dprintk(VIDC_ERR, "Failed to get memory client\n");
-		rc = -ENOMEM;
-		goto exit;
-	}
-	binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-	if (!binfo) {
-		dprintk(VIDC_ERR, "Out of memory\n");
-		rc = -ENOMEM;
-		goto exit;
-	}
-	if (b->length > VIDEO_MAX_PLANES) {
-		dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
-			b->length, VIDEO_MAX_PLANES);
-		rc = -EINVAL;
-		goto exit;
-	}
-	for (i = 0; i < b->length; ++i) {
-		if (EXTRADATA_IDX(b->length) &&
-			(i == EXTRADATA_IDX(b->length)) &&
-			!b->m.planes[i].length) {
-			continue;
-		}
-		temp = get_registered_buf(&v4l2_inst->registered_bufs,
-				b->m.planes[i].reserved[0],
-				b->m.planes[i].reserved[1],
-				b->m.planes[i].length, &plane);
-		if (temp) {
-			dprintk(VIDC_DBG,
-				"This memory region has already been prepared\n");
-			rc = -EINVAL;
-			kfree(binfo);
-			goto exit;
-		}
-
-		if (vidc_inst->session_type == MSM_VIDC_DECODER) {
-			if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-				buffer_type = HAL_BUFFER_INPUT;
-			else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
-				buffer_type = HAL_BUFFER_OUTPUT;
-		} else {
-			/* FIXME in the future.  See comment in msm_comm_get_\
-			 * domain_partition. Same problem here. */
-			if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-				buffer_type = HAL_BUFFER_OUTPUT;
-			else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
-				buffer_type = HAL_BUFFER_INPUT;
-		}
-
-		temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
-				b->m.planes[i].reserved[0], &plane);
-
-		if (temp) {
-			binfo->type = b->type;
-			binfo->fd[i] = b->m.planes[i].reserved[0];
-			binfo->buff_off[i] = b->m.planes[i].reserved[1];
-			binfo->size[i] = b->m.planes[i].length;
-			binfo->uvaddr[i] = b->m.planes[i].m.userptr;
-			binfo->device_addr[i] =
-			temp->handle[plane]->device_addr + binfo->buff_off[i];
-			binfo->handle[i] = NULL;
-		} else {
-			handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
-					b->m.planes[i].reserved[0],
-					b->m.planes[i].reserved[1],
-					buffer_type);
-			if (!handle) {
-				dprintk(VIDC_ERR,
-					"Failed to get device buffer address\n");
-				kfree(binfo);
-				goto exit;
-			}
-			binfo->type = b->type;
-			binfo->fd[i] = b->m.planes[i].reserved[0];
-			binfo->buff_off[i] = b->m.planes[i].reserved[1];
-			binfo->size[i] = b->m.planes[i].length;
-			binfo->uvaddr[i] = b->m.planes[i].m.userptr;
-			binfo->device_addr[i] =
-				handle->device_addr + binfo->buff_off[i];
-			binfo->handle[i] = handle;
-			dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
-					b->m.planes[i].reserved[0],
-					b->m.planes[i].reserved[1],
-					b->m.planes[i].length);
-			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
-				binfo->handle[i], SMEM_CACHE_CLEAN);
-			if (rc)
-				dprintk(VIDC_WARN,
-					"CACHE Clean failed: %d, %d, %d\n",
-					b->m.planes[i].reserved[0],
-					b->m.planes[i].reserved[1],
-					b->m.planes[i].length);
-		}
-		b->m.planes[i].m.userptr = binfo->device_addr[i];
-	}
-	binfo->num_planes = b->length;
-	list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
-	rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
-exit:
-	return rc;
+	return msm_vidc_prepare_buf(get_vidc_inst(file, fh), b);
 }
 
 int msm_v4l2_qbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	struct msm_vidc_inst *vidc_inst;
-	struct msm_v4l2_vid_inst *v4l2_inst;
-	struct buffer_info *binfo;
-	int plane = 0;
-	int rc = 0;
-	int i;
-	if (b->length > VIDEO_MAX_PLANES) {
-		dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
-			b->length);
-		return -EINVAL;
-	}
-	vidc_inst = get_vidc_inst(file, fh);
-	v4l2_inst = get_v4l2_inst(file, fh);
-	for (i = 0; i < b->length; ++i) {
-		if (EXTRADATA_IDX(b->length) &&
-			(i == EXTRADATA_IDX(b->length)) &&
-			!b->m.planes[i].length) {
-			b->m.planes[i].m.userptr = 0;
-			continue;
-		}
-		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
-				b->m.planes[i].reserved[0],
-				b->m.planes[i].reserved[1],
-				b->m.planes[i].length, &plane);
-		if (!binfo) {
-			dprintk(VIDC_ERR,
-				"This buffer is not registered: %d, %d, %d\n",
-				b->m.planes[i].reserved[0],
-				b->m.planes[i].reserved[1],
-				b->m.planes[i].length);
-			rc = -EINVAL;
-			goto err_invalid_buff;
-		}
-		b->m.planes[i].m.userptr = binfo->device_addr[i];
-		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
-				binfo->device_addr[i]);
-		if (binfo->handle[i] &&
-			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
-			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
-					binfo->handle[i], SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"Failed to clean caches: %d\n", rc);
-				goto err_invalid_buff;
-			}
-		}
-	}
-	rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
-err_invalid_buff:
-	return rc;
+	return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
 }
 
 int msm_v4l2_dqbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
-	int rc = 0;
-	int i;
-	struct msm_v4l2_vid_inst *v4l2_inst;
-	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
-	struct buffer_info *buffer_info;
-	if (b->length > VIDEO_MAX_PLANES) {
-		dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
-			b->length);
-		return -EINVAL;
-	}
-	v4l2_inst = get_v4l2_inst(file, fh);
-	rc = msm_vidc_dqbuf((void *)vidc_inst, b);
-	if (rc) {
-		dprintk(VIDC_DBG,
-			"Failed to dqbuf, capability: %d, rc: %d\n",
-			b->type, rc);
-		goto fail_dq_buf;
-	}
-	for (i = 0; i < b->length; i++) {
-		if (EXTRADATA_IDX(b->length) &&
-				(i == EXTRADATA_IDX(b->length)) &&
-				!b->m.planes[i].m.userptr) {
-			continue;
-		}
-		buffer_info = device_to_uvaddr(
-				&v4l2_inst->registered_bufs,
-				b->m.planes[i].m.userptr);
-		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
-		if (!b->m.planes[i].m.userptr) {
-			dprintk(VIDC_ERR,
-			"Failed to find user virtual address, 0x%lx, %d, %d\n",
-			b->m.planes[i].m.userptr, b->type, i);
-			rc = -EINVAL;
-			goto fail_dq_buf;
-		}
-		if (buffer_info->handle[i] &&
-			(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
-			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
-				buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"Failed to clean caches: %d\n", rc);
-				goto fail_dq_buf;
-			}
-		}
-	}
-fail_dq_buf:
-	return rc;
+	return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
 }
 
 int msm_v4l2_streamon(struct file *file, void *fh,
@@ -616,12 +184,10 @@
 static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
 				struct v4l2_decoder_cmd *dec)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
 	int rc = 0;
-	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (dec->cmd == V4L2_DEC_CMD_STOP)
-		rc = msm_v4l2_release_buffers(v4l2_inst,
+		rc = msm_vidc_release_buffers(vidc_inst,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
@@ -632,12 +198,10 @@
 static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
 				struct v4l2_encoder_cmd *enc)
 {
-	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
 	int rc = 0;
-	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (enc->cmd == V4L2_ENC_CMD_STOP)
-		rc = msm_v4l2_release_buffers(v4l2_inst,
+		rc = msm_vidc_release_buffers(vidc_inst,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 73ff9fa..5e7c84c 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -12,7 +12,7 @@
  */
 
 #include <linux/slab.h>
-
+#include <mach/scm.h>
 #include "msm_vidc_internal.h"
 #include "msm_vidc_common.h"
 #include "vidc_hfi_api.h"
@@ -24,6 +24,14 @@
 #define MAX_NUM_OUTPUT_BUFFERS 6
 #define DEFAULT_CONCEAL_COLOR 0x0
 
+#define TZ_INFO_GET_FEATURE_VERSION_ID 0x3
+#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
+#define TZ_FEATURE_VERSION(major, minor, patch) \
+	(((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+struct tz_get_feature_version {
+	u32 feature_id;
+};
+
 enum msm_vdec_ctrl_cluster {
 	MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
 };
@@ -72,6 +80,7 @@
 static const char *const mpeg_vidc_video_alloc_mode_type[] = {
 	"Buffer Allocation Static",
 	"Buffer Allocation Ring Buffer",
+	"Buffer Allocation Dynamic Buffer"
 };
 
 static const char *const perf_level[] = {
@@ -255,15 +264,32 @@
 		.step = 0,
 	},
 	{
-		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE,
-		.name = "Buffer allocation mode",
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
+		.name = "Buffer allocation mode for input",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
-		.maximum = V4L2_MPEG_VIDC_VIDEO_RING,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
 		.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
 		.menu_skip_mask = ~(
 			(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
-			(1 << V4L2_MPEG_VIDC_VIDEO_RING)
+			(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+			),
+		.qmenu = mpeg_vidc_video_alloc_mode_type,
+		.step = 0,
+		.cluster = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
+		.name = "Buffer allocation mode for output",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
 			),
 		.qmenu = mpeg_vidc_video_alloc_mode_type,
 		.step = 0,
@@ -363,6 +389,14 @@
 		.type = OUTPUT_PORT,
 	},
 	{
+		.name = "HEVC_HYBRID",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
 		.name = "VP8",
 		.description = "VP8 compressed format",
 		.fourcc = V4L2_PIX_FMT_VP8,
@@ -683,12 +717,7 @@
 		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) {
@@ -804,13 +833,14 @@
 	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);
 		return -EINVAL;
 	}
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		struct hal_frame_size frame_sz;
 
 		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
 			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
@@ -823,13 +853,6 @@
 			goto err_invalid_fmt;
 		}
 		inst->fmts[fmt->type] = fmt;
-		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);
-		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) {
@@ -894,9 +917,14 @@
 		frame_sz.width = inst->prop.width;
 		frame_sz.height = inst->prop.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] =
@@ -1029,15 +1057,13 @@
 			mutex_unlock(&inst->lock);
 			break;
 		}
-		if (*num_buffers && *num_buffers >=
-			bufreq->buffer_count_actual) {
+		*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_count_actual = *num_buffers;
 			rc = call_hfi_op(hdev, session_set_property,
 				inst->session, property_id, &new_buf_count);
-		} else {
-			*num_buffers = bufreq->buffer_count_min;
 		}
 		mutex_unlock(&inst->lock);
 		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
@@ -1293,21 +1319,60 @@
 	inst->capability.height.max = DEFAULT_HEIGHT;
 	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
 	inst->capability.width.max = DEFAULT_WIDTH;
+	inst->capability.buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->capability.buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
 	inst->prop.fps = 30;
 	return rc;
 }
 
+static inline enum buffer_mode_type get_buf_type(int val)
+{
+	switch (val) {
+	case V4L2_MPEG_VIDC_VIDEO_STATIC:
+		return HAL_BUFFER_MODE_STATIC;
+	case V4L2_MPEG_VIDC_VIDEO_RING:
+		return HAL_BUFFER_MODE_RING;
+	case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
+		return HAL_BUFFER_MODE_DYNAMIC;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid buf type: %d", __func__, val);
+	}
+	return 0;
+}
+
+static int check_tz_dynamic_buffer_support(void)
+{
+	int rc = 0;
+	struct tz_get_feature_version tz_feature_id;
+	unsigned int resp = 0;
+
+	tz_feature_id.feature_id = TZ_DYNAMIC_BUFFER_FEATURE_ID;
+	rc = scm_call(SCM_SVC_INFO,
+		  TZ_INFO_GET_FEATURE_VERSION_ID, &tz_feature_id,
+		  sizeof(tz_feature_id), &resp, sizeof(resp));
+	if ((rc) || (resp != TZ_FEATURE_VERSION(1, 1, 0))) {
+		dprintk(VIDC_DBG,
+			"Dyamic buffer mode not supported, failed to get tz feature version id : %u, rc : %d, response : %u\n",
+			tz_feature_id.feature_id, rc, resp);
+		rc = -ENOTSUPP;
+	}
+	return rc;
+}
+
 static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
 {
 	int rc = 0;
 	struct hal_nal_stream_format_supported stream_format;
 	struct hal_enable_picture enable_picture;
-	struct hal_enable hal_property;/*, prop;*/
+	struct hal_enable hal_property;
 	enum hal_property property_id = 0;
 	u32 property_val = 0;
 	void *pdata = NULL;
 	struct hfi_device *hdev;
 	struct hal_extradata_enable extra;
+	struct hal_buffer_alloc_mode alloc_mode;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1396,15 +1461,17 @@
 		}
 
 		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE:
-	{
-		struct hal_buffer_alloc_mode mode;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
+		if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
+			rc = -ENOTSUPP;
+			break;
+		}
 		property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
-		mode.buffer_mode = ctrl->val;
-		mode.buffer_type = HAL_BUFFER_INPUT;
-		pdata = &mode;
+		alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+		alloc_mode.buffer_type = HAL_BUFFER_INPUT;
+		inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
+		pdata = &alloc_mode;
 		break;
-	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
 	{
 		property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
@@ -1412,6 +1479,28 @@
 		pdata = &hal_property;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
+		property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+		alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+		if (!(alloc_mode.buffer_mode &
+			inst->capability.buffer_mode[CAPTURE_PORT])) {
+			dprintk(VIDC_DBG,
+				"buffer mode[%d] not supported for Capture Port\n",
+				ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		if ((alloc_mode.buffer_mode == HAL_BUFFER_MODE_DYNAMIC) &&
+			(inst->flags & VIDC_SECURE) &&
+			check_tz_dynamic_buffer_support()) {
+				rc = -ENOTSUPP;
+				break;
+		}
+		alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
+		pdata = &alloc_mode;
+		inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
+		break;
+
 	default:
 		break;
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c1a9ad0..b94d9db 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
@@ -1257,8 +1257,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 +1271,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 +1288,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;
@@ -1953,6 +1963,8 @@
 	inst->prop.height = DEFAULT_HEIGHT;
 	inst->prop.width = 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;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 10a0eac..f2f0f5d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -199,6 +199,480 @@
 	return -EINVAL;
 }
 
+struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
+		struct v4l2_buffer *b, int idx, int *plane)
+{
+	struct buffer_info *temp;
+	struct buffer_info *ret = NULL;
+	int i;
+	struct list_head *list = &inst->registered_bufs;
+	int fd = b->m.planes[idx].reserved[0];
+	u32 buff_off = b->m.planes[idx].reserved[1];
+	u32 size = b->m.planes[idx].length;
+	u32 device_addr = b->m.planes[idx].m.userptr;
+
+	if (!list || fd < 0 || !plane) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		goto err_invalid_input;
+	}
+
+	*plane = 0;
+	mutex_lock(&inst->lock);
+	list_for_each_entry(temp, list, list) {
+		for (i = 0; (i < temp->num_planes)
+			&& (i < VIDEO_MAX_PLANES); i++) {
+			if (temp &&
+				((fd == temp->fd[i]) ||
+				(device_addr == temp->device_addr[i])) &&
+				(CONTAINS(temp->buff_off[i],
+				temp->size[i], buff_off)
+				|| CONTAINS(buff_off,
+				size, temp->buff_off[i])
+				|| OVERLAPS(buff_off, size,
+				temp->buff_off[i],
+				temp->size[i]))) {
+					dprintk(VIDC_DBG,
+						"This memory region is already mapped\n");
+					ret = temp;
+					*plane = i;
+					break;
+			}
+		}
+		if (ret)
+			break;
+	}
+	mutex_unlock(&inst->lock);
+err_invalid_input:
+	return ret;
+}
+
+struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst,
+			struct list_head *list, int fd, int *plane)
+{
+	struct buffer_info *temp;
+	struct buffer_info *ret = NULL;
+	int i;
+	if (fd == 0)
+		return NULL;
+	if (!list || fd < 0 || !plane) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		goto err_invalid_input;
+	}
+	*plane = 0;
+	mutex_lock(&inst->lock);
+	list_for_each_entry(temp, list, list) {
+		for (i = 0; (i < temp->num_planes)
+			&& (i < VIDEO_MAX_PLANES); i++) {
+			if (temp && temp->fd[i] == fd)  {
+				temp->same_fd_ref[i]++;
+				dprintk(VIDC_INFO,
+				"Found same fd buffer\n");
+				ret = temp;
+				*plane = i;
+				break;
+			}
+		}
+		if (ret)
+			break;
+	}
+	mutex_unlock(&inst->lock);
+err_invalid_input:
+	return ret;
+}
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
+				struct list_head *list, u32 device_addr)
+{
+	struct buffer_info *temp = NULL;
+	struct buffer_info *dummy = NULL;
+	int found = 0;
+	int i;
+	if (!list || !device_addr || !inst) {
+		dprintk(VIDC_ERR,
+			"Invalid input- list: %p device_addr: %u inst: %p\n",
+			list, device_addr, inst);
+		goto err_invalid_input;
+	}
+	mutex_lock(&inst->lock);
+	list_for_each_entry_safe(temp, dummy, list, list) {
+		for (i = 0; (i < temp->num_planes)
+			&& (i < VIDEO_MAX_PLANES); i++) {
+			if (temp && !temp->inactive &&
+				temp->device_addr[i] == device_addr)  {
+				dprintk(VIDC_INFO,
+				"Found same fd buffer\n");
+				found = 1;
+				break;
+			}
+		}
+		if (found)
+			break;
+	}
+	mutex_unlock(&inst->lock);
+err_invalid_input:
+	return temp;
+}
+
+static inline void populate_buf_info(struct buffer_info *binfo,
+			struct v4l2_buffer *b, u32 i)
+{
+	binfo->type = b->type;
+	binfo->fd[i] = b->m.planes[i].reserved[0];
+	binfo->buff_off[i] = b->m.planes[i].reserved[1];
+	binfo->size[i] = b->m.planes[i].length;
+	binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+	binfo->num_planes = b->length;
+	binfo->memory = b->memory;
+	binfo->v4l2_index = b->index;
+	binfo->dequeued = false;
+	binfo->timestamp.tv_sec = b->timestamp.tv_sec;
+	binfo->timestamp.tv_usec = b->timestamp.tv_usec;
+	dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
+			__func__, i, binfo->fd[0], b->index);
+}
+
+static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
+					struct buffer_info *binfo)
+{
+	int i = 0;
+	b->type = binfo->type;
+	b->length = binfo->num_planes;
+	b->memory = binfo->memory;
+	b->index = binfo->v4l2_index;
+	b->timestamp.tv_sec = binfo->timestamp.tv_sec;
+	b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+	for (i = 0; i < binfo->num_planes; ++i) {
+		b->m.planes[i].reserved[0] = binfo->fd[i];
+		b->m.planes[i].reserved[1] = binfo->buff_off[i];
+		b->m.planes[i].length = binfo->size[i];
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
+		dprintk(VIDC_DBG, "%s %d %d %d %u\n", __func__, binfo->fd[i],
+				binfo->buff_off[i], binfo->size[i],
+				binfo->device_addr[i]);
+	}
+}
+
+static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
+		struct v4l2_plane *p, enum hal_buffer buffer_type)
+{
+	struct msm_smem *handle = NULL;
+	handle = msm_smem_user_to_kernel(inst->mem_client,
+				p->reserved[0],
+				p->reserved[1],
+				buffer_type);
+	if (!handle) {
+		dprintk(VIDC_ERR,
+			"%s: Failed to get device buffer address\n", __func__);
+		return NULL;
+	}
+	if (msm_smem_cache_operations(inst->mem_client, handle,
+			SMEM_CACHE_CLEAN))
+		dprintk(VIDC_WARN,
+			"CACHE Clean failed: %d, %d, %d\n",
+				p->reserved[0],
+				p->reserved[1],
+				p->length);
+	return handle;
+}
+
+static inline enum hal_buffer get_hal_buffer_type(
+		struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			return HAL_BUFFER_INPUT;
+		else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+			return HAL_BUFFER_OUTPUT;
+	} else {
+		/* FIXME in the future.  See comment in msm_comm_get_\
+		 * domain_partition. Same problem here. */
+		if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			return HAL_BUFFER_OUTPUT;
+		else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+			return HAL_BUFFER_INPUT;
+	}
+	return -EINVAL;
+}
+
+static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
+				struct msm_vidc_inst *inst)
+{
+	return ((b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+		(inst->buffer_mode_set[CAPTURE_PORT] ==
+		HAL_BUFFER_MODE_DYNAMIC));
+}
+
+
+static inline void save_v4l2_buffer(struct v4l2_buffer *b,
+						struct buffer_info *binfo)
+{
+	int i = 0;
+	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			continue;
+		}
+		populate_buf_info(binfo, b, i);
+	}
+}
+
+int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buffer_info *binfo = NULL;
+	struct buffer_info *temp = NULL;
+	int plane = 0;
+	int i = 0, rc = 0;
+
+	if (!b || !inst) {
+		dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+	if (!binfo) {
+		dprintk(VIDC_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+			b->length, VIDEO_MAX_PLANES);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	dprintk(VIDC_DBG, "[MAP] Create binfo = %p fd = %d type = %d\n",
+			binfo, b->m.planes[0].reserved[0], b->type);
+
+	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!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;
+		}
+
+		if (temp && is_dynamic_output_buffer_mode(b, inst) &&
+			(i == 0)) {
+			/*
+			* Buffer is already present in registered list
+			* increment ref_count, populate new values of v4l2
+			* buffer in existing buffer_info struct.
+			*
+			* We will use the saved buffer info and queue it when
+			* we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
+			*/
+			dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
+			rc = buf_ref_get(inst, temp);
+			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);
+
+		populate_buf_info(binfo, b, i);
+		if (temp) {
+			binfo->device_addr[i] =
+			temp->handle[plane]->device_addr + binfo->buff_off[i];
+			b->m.planes[i].m.userptr = binfo->device_addr[i];
+			binfo->mapped[i] = false;
+		} else {
+			if (inst->map_output_buffer) {
+				binfo->handle[i] =
+					map_buffer(inst, &b->m.planes[i],
+						get_hal_buffer_type(inst, b));
+				if (!binfo->handle[i]) {
+					rc = -EINVAL;
+					goto exit;
+				}
+				dprintk(VIDC_DBG,
+					"[MAP] - mapped handle[%d] = %p fd[%d] = %d",
+					i, binfo->handle[i], i, binfo->fd[i]);
+				binfo->mapped[i] = true;
+				binfo->device_addr[i] =
+					binfo->handle[i]->device_addr +
+					binfo->buff_off[i];
+				b->m.planes[i].m.userptr =
+					binfo->device_addr[i];
+			} else {
+				binfo->device_addr[i] =
+					b->m.planes[i].m.userptr;
+			}
+			dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
+					b->m.planes[i].reserved[0],
+					b->m.planes[i].reserved[1],
+					b->m.planes[i].length);
+		}
+		/* We maintain one ref count for all planes*/
+		if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) {
+			rc = buf_ref_get(inst, binfo);
+			if (rc < 0)
+				return rc;
+		}
+	}
+	dprintk(VIDC_DBG, "[MAP] Adding binfo = %p to list\n", binfo);
+	mutex_lock(&inst->lock);
+	list_add_tail(&binfo->list, &inst->registered_bufs);
+	mutex_unlock(&inst->lock);
+	return 0;
+exit:
+	kfree(binfo);
+	return rc;
+}
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo)
+{
+	int i = 0;
+	struct buffer_info *temp = NULL;
+	struct buffer_info *dummy = NULL;
+	struct list_head *list;
+	bool found = false, keep_node = false;
+
+	if (!inst || !binfo) {
+		dprintk(VIDC_ERR, "%s invalid param: %p %p\n",
+			__func__, inst, binfo);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->lock);
+	list = &inst->registered_bufs;
+	/*
+	* Make sure the buffer to be unmapped and deleted
+	* from the registered list is present in the list.
+	*/
+	list_for_each_entry_safe(temp, dummy, list, list) {
+		if (temp == binfo) {
+			found = true;
+			break;
+		}
+	}
+
+	/*
+	* Free the buffer info only if
+	* - buffer info has not been deleted from registered list
+	* - vidc client has called dqbuf on the buffer
+	* - no references are held on the buffer
+	*/
+	if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
+		goto exit;
+
+	for (i = 0; i < temp->num_planes; i++) {
+		/*
+		* Unmap the handle only if the buffer has been mapped and no
+		* other buffer has a reference to this buffer.
+		* In case of buffers with same fd, we will map the buffer only
+		* once and subsequent buffers will refer to the mapped buffer's
+		* device address.
+		* For buffers which share the same fd, do not unmap and keep
+		* the buffer info in registered list.
+		*/
+		if (temp->handle[i] && temp->mapped[i] &&
+			!temp->same_fd_ref[i]) {
+			dprintk(VIDC_DBG,
+				"[UNMAP] - handle[%d] = %p fd[%d] = %d",
+				i, temp->handle[i], i, temp->fd[i]);
+			msm_smem_free(inst->mem_client,
+				temp->handle[i]);
+		}
+
+		if (temp->same_fd_ref[i])
+			keep_node = true;
+		else {
+			temp->fd[i] = 0;
+			temp->handle[i] = 0;
+			temp->device_addr[i] = 0;
+			temp->uvaddr[i] = 0;
+		}
+	}
+	if (!keep_node) {
+		dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %p\n", temp);
+		list_del(&temp->list);
+		kfree(temp);
+	} else {
+		temp->inactive = true;
+		dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %p\n", temp);
+	}
+exit:
+	mutex_unlock(&inst->lock);
+	return 0;
+}
+
+
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo)
+{
+	struct v4l2_buffer b = {0};
+	struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
+
+	if (!binfo) {
+		dprintk(VIDC_ERR, "%s invalid param: %p\n", __func__, binfo);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
+
+	b.m.planes = plane;
+	repopulate_v4l2_buffer(&b, binfo);
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_qbuf(inst, &b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_qbuf(inst, &b);
+
+	return -EINVAL;
+}
+
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+				struct buffer_info *binfo)
+{
+	int i = 0;
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+		return -EINVAL;
+	}
+
+	if (!inst->map_output_buffer)
+		return 0;
+
+	if (!binfo) {
+		dprintk(VIDC_ERR, "%s: invalid buffer info: %p\n",
+			__func__, inst);
+		return -EINVAL;
+	}
+
+	if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return 0;
+
+
+	for (i = 0; i < binfo->num_planes; i++) {
+		if (binfo->handle[i]) {
+			rc = msm_smem_cache_operations(inst->mem_client,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s: Failed to clean caches: %d\n",
+					__func__, rc);
+				return -EINVAL;
+			}
+		}
+	}
+	return 0;
+}
+
 int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -206,6 +680,19 @@
 	if (!inst || !b)
 		return -EINVAL;
 
+	if (is_dynamic_output_buffer_mode(b, inst)) {
+		dprintk(VIDC_ERR, "%s: not supported in dynamic buffer mode\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	/* Map the buffer only for non-kernel clients*/
+	if (b->m.planes[0].reserved[0]) {
+		inst->map_output_buffer = true;
+		if (map_and_register_buf(inst, b))
+			return -EINVAL;
+	}
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_prepare_buf(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
@@ -213,18 +700,58 @@
 	return -EINVAL;
 }
 
-int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
+int msm_vidc_release_buffers(void *instance, int buffer_type)
 {
+	struct list_head *ptr, *next;
 	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *bi;
+	struct v4l2_buffer buffer_info;
+	struct v4l2_plane plane[VIDEO_MAX_PLANES];
+	int i, rc = 0;
 
-	if (!inst || !b)
+	if (!inst)
 		return -EINVAL;
 
-	if (inst->session_type == MSM_VIDC_DECODER)
-		return msm_vdec_release_buf(instance, b);
-	if (inst->session_type == MSM_VIDC_ENCODER)
-		return msm_venc_release_buf(instance, b);
-	return -EINVAL;
+	list_for_each_safe(ptr, next, &inst->registered_bufs) {
+		bi = list_entry(ptr, struct buffer_info, list);
+		if (bi->type == buffer_type) {
+			buffer_info.type = bi->type;
+			for (i = 0; (i < bi->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				plane[i].reserved[0] = bi->fd[i];
+				plane[i].reserved[1] = bi->buff_off[i];
+				plane[i].length = bi->size[i];
+				plane[i].m.userptr = bi->device_addr[i];
+				buffer_info.m.planes = plane;
+				dprintk(VIDC_DBG,
+					"Releasing buffer: %d, %d, %d\n",
+					buffer_info.m.planes[i].reserved[0],
+					buffer_info.m.planes[i].reserved[1],
+					buffer_info.m.planes[i].length);
+			}
+			buffer_info.length = bi->num_planes;
+			if (inst->session_type == MSM_VIDC_DECODER)
+				rc = msm_vdec_release_buf(instance,
+					&buffer_info);
+			if (inst->session_type == MSM_VIDC_ENCODER)
+				rc = msm_venc_release_buf(instance,
+					&buffer_info);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed Release buffer: %d, %d, %d\n",
+					buffer_info.m.planes[0].reserved[0],
+					buffer_info.m.planes[0].reserved[1],
+					buffer_info.m.planes[0].length);
+			list_del(&bi->list);
+			for (i = 0; i < bi->num_planes; i++) {
+				if (bi->handle[i])
+					msm_smem_free(inst->mem_client,
+							bi->handle[i]);
+			}
+			kfree(bi);
+		}
+	}
+	return rc;
 }
 
 int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
@@ -246,29 +773,149 @@
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *binfo;
+	int plane = 0;
+	int rc = 0;
+	int i;
 
 	if (!inst || !b)
 		return -EINVAL;
 
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
+			b->length);
+		return -EINVAL;
+	}
+
+	if (is_dynamic_output_buffer_mode(b, inst)) {
+		if (b->m.planes[0].reserved[0])
+			inst->map_output_buffer = true;
+
+		rc = map_and_register_buf(inst, b);
+		if (rc == -EEXIST)
+			return 0;
+		if (rc)
+			return rc;
+	}
+
+	for (i = 0; i < b->length; ++i) {
+		if (!inst->map_output_buffer)
+			continue;
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			b->m.planes[i].m.userptr = 0;
+			continue;
+		}
+
+		binfo = get_registered_buf(inst, b, i, &plane);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+				"This buffer is not registered: %d, %d, %d\n",
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+			goto err_invalid_buff;
+		}
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
+		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
+				binfo->device_addr[i]);
+
+		if ((inst->fmts[OUTPUT_PORT]->fourcc ==
+			V4L2_PIX_FMT_HEVC_HYBRID) &&  binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+			rc = msm_smem_cache_operations(inst->mem_client,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to inv caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
+
+		if (binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+			rc = msm_smem_cache_operations(inst->mem_client,
+					binfo->handle[i], SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to clean caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
+	}
+
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_qbuf(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
 		return msm_venc_qbuf(instance, b);
+
+err_invalid_buff:
 	return -EINVAL;
 }
 
 int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *buffer_info = NULL;
+	int i = 0, rc = 0;
 
 	if (!inst || !b)
 		return -EINVAL;
 
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
+			b->length);
+		return -EINVAL;
+	}
+
 	if (inst->session_type == MSM_VIDC_DECODER)
-		return msm_vdec_dqbuf(instance, b);
+		rc = msm_vdec_dqbuf(instance, b);
 	if (inst->session_type == MSM_VIDC_ENCODER)
-		return msm_venc_dqbuf(instance, b);
-	return -EINVAL;
+		rc = msm_venc_dqbuf(instance, b);
+
+	if (rc)
+		return rc;
+
+	for (i = 0; i < b->length; i++) {
+		if (!inst->map_output_buffer)
+			continue;
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].m.userptr) {
+			continue;
+		}
+		buffer_info = device_to_uvaddr(inst,
+			&inst->registered_bufs,
+			b->m.planes[i].m.userptr);
+
+		if (!buffer_info) {
+			dprintk(VIDC_ERR,
+				"%s no buffer info registered for buffer addr: 0x%lx\n",
+				__func__, b->m.planes[i].m.userptr);
+			return -EINVAL;
+		}
+
+		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
+		if (!b->m.planes[i].m.userptr) {
+			dprintk(VIDC_ERR,
+			"%s: Failed to find user virtual address, 0x%lx, %d, %d\n",
+			__func__, b->m.planes[i].m.userptr, b->type, i);
+			return -EINVAL;
+		}
+	}
+
+	if (is_dynamic_output_buffer_mode(b, inst)) {
+		mutex_lock(&inst->lock);
+		buffer_info->dequeued = true;
+		mutex_unlock(&inst->lock);
+		dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
+			buffer_info->fd[0]);
+		rc = unmap_and_deregister_buf(inst, buffer_info);
+	} else
+		rc = output_buffer_cache_invalidate(inst, buffer_info);
+
+	return rc;
 }
 
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
@@ -450,9 +1097,11 @@
 	INIT_LIST_HEAD(&inst->internalbufs);
 	INIT_LIST_HEAD(&inst->persistbufs);
 	INIT_LIST_HEAD(&inst->ctrl_clusters);
+	INIT_LIST_HEAD(&inst->registered_bufs);
 	init_waitqueue_head(&inst->kernel_event_queue);
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
+	inst->map_output_buffer = false;
 
 	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
 		i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
@@ -495,7 +1144,7 @@
 	inst->debugfs_root =
 		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
 
-	setup_event_queue(inst, &core->vdev[core_id].vdev);
+	setup_event_queue(inst, &core->vdev[session_type].vdev);
 
 	mutex_lock(&core->sync_lock);
 	list_add_tail(&inst->list, &core->instances);
@@ -572,12 +1221,27 @@
 	struct msm_vidc_inst *temp;
 	struct msm_vidc_core *core;
 	struct list_head *ptr, *next;
+	struct buffer_info *bi;
 	int rc = 0;
 	int i;
 
 	if (!inst)
 		return -EINVAL;
 
+	list_for_each_safe(ptr, next, &inst->registered_bufs) {
+		bi = list_entry(ptr, struct buffer_info, list);
+		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			list_del(&bi->list);
+			for (i = 0; (i < bi->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				if (bi->handle[i])
+					msm_smem_free(inst->mem_client,
+							bi->handle[i]);
+			}
+			kfree(bi);
+		}
+	}
+
 	core = inst->core;
 	mutex_lock(&core->sync_lock);
 	list_for_each_safe(ptr, next, &core->instances) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 122f0e9..bf1c2cf 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -31,6 +31,8 @@
 		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
 #define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
 		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \
+		V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
 
 #define NUM_MBS_PER_SEC(__height, __width, __fps) ({\
 	(__height >> 4) * (__width >> 4) * __fps; \
@@ -430,6 +432,8 @@
 			inst->capability.frame_rate =
 				session_init_done->frame_rate;
 			inst->capability.capability_set = true;
+			inst->capability.buffer_mode[CAPTURE_PORT] =
+				session_init_done->alloc_mode_out;
 		} else {
 			dprintk(VIDC_ERR,
 				"Session init response from FW : 0x%x",
@@ -469,14 +473,74 @@
 		case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
 			event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
 			break;
+		case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
+			{
+				struct v4l2_event buf_event = {0};
+				struct buffer_info *binfo = NULL;
+				u32 *ptr = NULL;
+
+				dprintk(VIDC_DBG,
+					"%s - inst: %p buffer: %p extra: %p\n",
+					__func__, inst,
+					event_notify->packet_buffer,
+					event_notify->exra_data_buffer);
+
+				/*
+				* Get the buffer_info entry for the
+				* device address.
+				*/
+				binfo = device_to_uvaddr(inst,
+					&inst->registered_bufs,
+					(u32)event_notify->packet_buffer);
+				if (!binfo) {
+					dprintk(VIDC_ERR,
+						"%s buffer not found in registered list\n",
+						__func__);
+					return;
+				}
+
+				/* Fill event data to be sent to client*/
+				buf_event.type =
+					V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+				ptr = (u32 *)buf_event.u.data;
+				ptr[0] = binfo->fd[0];
+				ptr[1] = binfo->buff_off[0];
+
+				dprintk(VIDC_DBG,
+					"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);
+
+				/*
+				* Release buffer and remove from list
+				* if reference goes to zero.
+				*/
+				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,
+					&buf_event);
+				wake_up(&inst->kernel_event_queue);
+				return;
+			}
 		default:
 			break;
 		}
 		if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+			dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n");
 			inst->reconfig_height = event_notify->height;
 			inst->reconfig_width = event_notify->width;
 			inst->in_reconfig = true;
 		} else {
+			dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
 			inst->prop.height = event_notify->height;
 			inst->prop.width = event_notify->width;
 		}
@@ -805,6 +869,107 @@
 	}
 }
 
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+	int cnt = 0;
+
+	if (!inst || !binfo)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	atomic_inc(&binfo->ref_count);
+	cnt = atomic_read(&binfo->ref_count);
+	if (cnt > 2) {
+		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]);
+	mutex_unlock(&inst->lock);
+	return cnt;
+}
+
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+	int rc = 0;
+	int cnt;
+	bool release_buf = false;
+	bool qbuf_again = false;
+
+	if (!inst || !binfo)
+		return -EINVAL;
+
+	mutex_lock(&inst->lock);
+	atomic_dec(&binfo->ref_count);
+	cnt = atomic_read(&binfo->ref_count);
+	dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+	if (cnt == 0)
+		release_buf = true;
+	else if (cnt == 1)
+		qbuf_again = true;
+	else {
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		cnt = -EINVAL;
+	}
+	mutex_unlock(&inst->lock);
+
+	if (cnt < 0)
+		return cnt;
+
+	rc = output_buffer_cache_invalidate(inst, binfo);
+	if (rc)
+		return rc;
+
+	if (release_buf) {
+		/*
+		* We can not delete binfo here as we need to set the user
+		* virtual address saved in binfo->uvaddr to the dequeued v4l2
+		* buffer.
+		*
+		* We will set the pending_deletion flag to true here and delete
+		* binfo from registered list in dqbuf after setting the uvaddr.
+		*/
+		dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
+			binfo->fd[0]);
+		binfo->pending_deletion = true;
+	} else if (qbuf_again) {
+		rc = qbuf_dynamic_buf(inst, binfo);
+		if (!rc)
+			return rc;
+	}
+	return cnt;
+}
+
+static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
+					u32 device_addr, u32 flags)
+{
+	struct buffer_info *binfo = NULL;
+
+	/*
+	 * Update reference count and release OR queue back the buffer,
+	 * only when firmware is not holding a reference.
+	 */
+	if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+		binfo = device_to_uvaddr(inst, &inst->registered_bufs,
+				device_addr);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+				"%s buffer not found in registered list\n",
+				__func__);
+			return;
+		}
+		if (flags & HAL_BUFFERFLAG_READONLY) {
+			dprintk(VIDC_DBG,
+				"_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, addr: 0x%x\n",
+				binfo->fd[0], device_addr);
+			buf_ref_put(inst, binfo);
+		}
+	}
+}
+
 static void handle_fbd(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_data_done *response = data;
@@ -848,6 +1013,10 @@
 		}
 		vb->v4l2_buf.flags = 0;
 
+		handle_dynamic_buffer(inst, (u32)fill_buf_done->packet_buffer1,
+					fill_buf_done->flags1);
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
@@ -1337,7 +1506,9 @@
 	case V4L2_PIX_FMT_HEVC:
 		codec = HAL_VIDEO_CODEC_HEVC;
 		break;
-
+	case V4L2_PIX_FMT_HEVC_HYBRID:
+		codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
 		codec = HAL_UNUSED_CODEC;
@@ -2396,6 +2567,70 @@
 	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
 	return;
 }
+
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+	struct buffer_info *binfo = NULL, *dummy = NULL;
+	struct list_head *list = NULL;
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+		return;
+
+	/*
+	* dynamic buffer mode:- if flush is called during seek
+	* driver should not queue any new buffer it has been holding.
+	*
+	* Each dynamic o/p buffer can have one of following ref_count:
+	* ref_count : 0 - f/w has released reference and sent fbd back.
+	*		  The buffer has been returned back to client.
+	*
+	* ref_count : 1 - f/w is holding reference. f/w may have released
+	*                 fbd as read_only OR fbd is pending. f/w will
+	*		  release reference before sending flush_done.
+	*
+	* ref_count : 2 - f/w is holding reference, f/w has released fbd as
+	*                 read_only, which client has queued back to driver.
+	*                 driver holds this buffer and will queue back
+	*                 only when f/w releases the reference. During
+	*		  flush_done, f/w will release the reference but driver
+	*		  should not queue back the buffer to f/w.
+	*		  Flush all buffers with ref_count 2.
+	*/
+	mutex_lock(&inst->lock);
+	if (!list_empty(&inst->registered_bufs)) {
+		struct v4l2_event buf_event = {0};
+		u32 *ptr = NULL;
+		list = &inst->registered_bufs;
+		list_for_each_entry_safe(binfo, dummy, list, list) {
+			if (binfo &&
+			(binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+			(atomic_read(&binfo->ref_count) == 2)) {
+				atomic_dec(&binfo->ref_count);
+				buf_event.type =
+				V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
+				ptr = (u32 *)buf_event.u.data;
+				ptr[0] = binfo->fd[0];
+				ptr[1] = binfo->buff_off[0];
+				ptr[2] = binfo->uvaddr[0];
+				ptr[3] = (u32) binfo->timestamp.tv_sec;
+				ptr[4] = (u32) binfo->timestamp.tv_usec;
+				ptr[5] = binfo->v4l2_index;
+				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);
+				wake_up(&inst->kernel_event_queue);
+			}
+		}
+	}
+	mutex_unlock(&inst->lock);
+}
+
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
 {
 	int rc =  0;
@@ -2440,6 +2675,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
@@ -2471,6 +2707,7 @@
 				kfree(temp);
 			}
 		}
+
 		/*Do not send flush in case of session_error */
 		if (!(inst->state == MSM_VIDC_CORE_INVALID &&
 			  core->state != VIDC_CORE_INVALID))
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 03136ae..5a18265 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -36,6 +36,10 @@
 	__buf.filled_size = 0; \
 })
 
+#define DYNAMIC_BUF_OWNER(__binfo) ({ \
+	atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\
+})
+
 static int core_info_open(struct inode *inode, struct file *file)
 {
 	file->private_data = inode->i_private;
@@ -82,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)]) ?
@@ -193,6 +209,37 @@
 	return 0;
 }
 
+static int publish_unreleased_reference(struct msm_vidc_inst *inst)
+{
+	struct buffer_info *temp = NULL;
+	struct buffer_info *dummy = NULL;
+	struct list_head *list = NULL;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	list = &inst->registered_bufs;
+	mutex_lock(&inst->lock);
+	if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+		list_for_each_entry_safe(temp, dummy, list, list) {
+			if (temp && temp->type ==
+			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+			!temp->inactive && atomic_read(&temp->ref_count)) {
+				write_str(&dbg_buf,
+				"\tpending buffer: 0x%x fd[0] = %d ref_count = %d held by: %s\n",
+				temp->device_addr[0],
+				temp->fd[0],
+				atomic_read(&temp->ref_count),
+				DYNAMIC_BUF_OWNER(temp));
+			}
+		}
+	}
+	mutex_unlock(&inst->lock);
+	return 0;
+}
+
 static ssize_t inst_info_read(struct file *file, char __user *buf,
 		size_t count, loff_t *ppos)
 {
@@ -221,6 +268,19 @@
 		write_str(
 		&dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
 		"Output" : "Capture");
+		switch (inst->buffer_mode_set[i]) {
+		case HAL_BUFFER_MODE_STATIC:
+			write_str(&dbg_buf, "buffer mode : %s\n", "static");
+			break;
+		case HAL_BUFFER_MODE_RING:
+			write_str(&dbg_buf, "buffer mode : %s\n", "ring");
+			break;
+		case HAL_BUFFER_MODE_DYNAMIC:
+			write_str(&dbg_buf, "buffer mode : %s\n", "dynamic");
+			break;
+		default:
+			write_str(&dbg_buf, "buffer mode : unsupported\n");
+		}
 		for (j = 0; j < inst->fmts[i]->num_planes; j++)
 			write_str(&dbg_buf, "size for plane %d: %u\n", j,
 			inst->bufq[i].vb2_bufq.plane_sizes[j]);
@@ -235,6 +295,8 @@
 	write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd);
 	write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb);
 	write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd);
+	publish_unreleased_reference(inst);
+
 	return simple_read_from_buffer(buf, count, ppos,
 		dbg_buf.ptr, dbg_buf.filled_size);
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 15f4e3f..b17cb5a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -14,7 +14,9 @@
 #ifndef _MSM_VIDC_INTERNAL_H_
 #define _MSM_VIDC_INTERNAL_H_
 
+#include <linux/atomic.h>
 #include <linux/list.h>
+#include <linux/time.h>
 #include <linux/types.h>
 #include <linux/completion.h>
 #include <linux/wait.h>
@@ -178,6 +180,7 @@
 	struct hal_capability_supported height;
 	struct hal_capability_supported frame_rate;
 	u32 capability_set;
+	enum buffer_mode_type buffer_mode[MAX_PORT_NUM];
 };
 
 struct msm_vidc_core {
@@ -227,6 +230,9 @@
 	struct buf_count count;
 	enum msm_vidc_modes flags;
 	struct msm_vidc_core_capability capability;
+	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
+	struct list_head registered_bufs;
+	bool map_output_buffer;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
@@ -256,4 +262,35 @@
 int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
 void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
 
+struct buffer_info {
+	struct list_head list;
+	int type;
+	int num_planes;
+	int fd[VIDEO_MAX_PLANES];
+	int buff_off[VIDEO_MAX_PLANES];
+	int size[VIDEO_MAX_PLANES];
+	u32 uvaddr[VIDEO_MAX_PLANES];
+	u32 device_addr[VIDEO_MAX_PLANES];
+	struct msm_smem *handle[VIDEO_MAX_PLANES];
+	enum v4l2_memory memory;
+	u32 v4l2_index;
+	bool pending_deletion;
+	atomic_t ref_count;
+	bool dequeued;
+	bool inactive;
+	bool mapped[VIDEO_MAX_PLANES];
+	int same_fd_ref[VIDEO_MAX_PLANES];
+	struct timeval timestamp;
+};
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
+			struct list_head *list, u32 device_addr);
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+				struct buffer_info *binfo);
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo);
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo);
 #endif
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index aaf1f50..4dbda32 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -829,6 +829,7 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	++device->clk_cnt;
 	return 0;
 fail_clk_enable:
 	for (i--; i >= 0; i--) {
@@ -858,6 +859,7 @@
 		clk_disable(cl->clk);
 	}
 	device->clocks_enabled = 0;
+	--device->clk_cnt;
 }
 
 static DECLARE_COMPLETION(pc_prep_done);
@@ -899,6 +901,7 @@
 		venus_hfi_unvote_buses(device, DDR_MEM);
 
 	device->power_enabled = 0;
+	--device->pwr_cnt;
 already_disabled:
 	return rc;
 }
@@ -949,6 +952,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);
@@ -2691,6 +2695,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
+	mutex_lock(&device->clk_pwr_lock);
 	if (device->clocks_enabled) {
 		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 			cl = &device->resources.clock[i];
@@ -2710,6 +2715,8 @@
 		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)
 {
@@ -2720,7 +2727,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-
+	mutex_lock(&device->clk_pwr_lock);
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
@@ -2734,12 +2741,15 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	++device->clk_cnt;
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 fail_clk_enable:
 	for (; i >= 0; i--) {
 		cl = &device->resources.clock[i];
 		clk_disable_unprepare(cl->clk);
 	}
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 }
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
@@ -3184,10 +3194,12 @@
 		goto fail_iommu_attach;
 	}
 
+	mutex_lock(&device->clk_pwr_lock);
 	if (!device->resources.fw.cookie) {
 		rc = regulator_enable(device->gdsc);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to enable GDSC %d", rc);
+			mutex_unlock(&device->clk_pwr_lock);
 			goto fail_enable_gdsc;
 		}
 		device->resources.fw.cookie = subsystem_get("venus");
@@ -3196,9 +3208,12 @@
 	if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
 		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
+		mutex_unlock(&device->clk_pwr_lock);
 		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*/
 	rc = venus_hfi_enable_clks(device);
@@ -3219,8 +3234,12 @@
 fail_enable_clks:
 	subsystem_put(device->resources.fw.cookie);
 fail_load_fw:
+	mutex_lock(&device->clk_pwr_lock);
 	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);
 fail_iommu_attach:
@@ -3239,8 +3258,12 @@
 		flush_workqueue(device->vidc_workq);
 		flush_workqueue(device->venus_pm_workq);
 		venus_hfi_disable_clks(device);
+		mutex_lock(&device->clk_pwr_lock);
 		subsystem_put(device->resources.fw.cookie);
 		regulator_disable(device->gdsc);
+		device->power_enabled = 0;
+		--device->pwr_cnt;
+		mutex_unlock(&device->clk_pwr_lock);
 		venus_hfi_interface_queues_release(dev);
 		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
@@ -3281,6 +3304,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);
@@ -3337,6 +3391,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");
@@ -3458,6 +3516,7 @@
 	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;
 }
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.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 5059273..70b93ff0 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -19,6 +19,7 @@
 
 #define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
 #define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
 
 #define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES	\
 	(HFI_OX_BASE + 0x1)
@@ -60,6 +61,7 @@
 
 #define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
 #define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
 
 #define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
 #define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
@@ -137,6 +139,10 @@
 	(HFI_PROPERTY_PARAM_OX_START + 0x008)
 #define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA	\
 	(HFI_PROPERTY_PARAM_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
+	(HFI_PROPERTY_PARAM_OX_START + 0x00A)
+#define  HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00B)
 
 #define HFI_PROPERTY_CONFIG_OX_START					\
 	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
@@ -278,6 +284,12 @@
 	u32 format;
 };
 
+struct hfi_buffer_alloc_mode_supported {
+	u32 buffer_type;
+	u32 num_entries;
+	u32 rg_data[1];
+};
+
 struct hfi_mb_error_map {
 	u32 error_map_size;
 	u8 rg_error_map[1];
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 890a5be..63e2036 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -202,6 +202,7 @@
 	HAL_VIDEO_CODEC_VP7      = 0x00000800,
 	HAL_VIDEO_CODEC_VP8      = 0x00001000,
 	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
+	HAL_VIDEO_CODEC_HEVC_HYBRID     = 0x00004000,
 	HAL_UNUSED_CODEC = 0x10000000,
 };
 
@@ -863,12 +864,14 @@
 enum hal_event_type {
 	HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
 	HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+	HAL_EVENT_RELEASE_BUFFER_REFERENCE,
 	HAL_UNUSED_SEQCHG = 0x10000000,
 };
 
 enum buffer_mode_type {
-	HAL_BUFFER_MODE_STATIC = 0x00000000,
-	HAL_BUFFER_MODE_RING,
+	HAL_BUFFER_MODE_STATIC = 0x001,
+	HAL_BUFFER_MODE_RING = 0x010,
+	HAL_BUFFER_MODE_DYNAMIC = 0x100,
 };
 
 struct hal_buffer_alloc_mode {
@@ -930,6 +933,8 @@
 	u32 height;
 	u32 width;
 	u32 hal_event_type;
+	u8 *packet_buffer;
+	u8 *exra_data_buffer;
 };
 
 /* Data callback structure */
@@ -1013,10 +1018,9 @@
 	struct hal_uncompressed_format_supported uncomp_format;
 	struct hal_interlace_format_supported HAL_format;
 	struct hal_nal_stream_format_supported nal_stream_format;
-/*	struct hal_profile_level_supported profile_level;
-	// allocate and released memory for above. */
 	struct hal_intra_refresh intra_refresh;
 	struct hal_seq_header_info seq_hdr_info;
+	enum buffer_mode_type alloc_mode_out;
 };
 
 struct buffer_requirements {
@@ -1041,6 +1045,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)
 
@@ -1094,6 +1106,7 @@
 	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,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index de312f4..6589a7cf 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -64,7 +64,12 @@
 
 #define HFI_ERR_SESSION_STREAM_CORRUPT		(HFI_COMMON_BASE + 0x100B)
 #define HFI_ERR_SESSION_ENC_OVERFLOW		(HFI_COMMON_BASE + 0x100C)
-#define  HFI_ERR_SESSION_UNSUPPORTED_STREAM	(HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_UNSUPPORTED_STREAM	(HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_CMDSIZE			(HFI_COMMON_BASE + 0x100E)
+#define HFI_ERR_SESSION_UNSUPPORT_CMD		(HFI_COMMON_BASE + 0x100F)
+#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE	(HFI_COMMON_BASE + 0x1010)
+#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL	(HFI_COMMON_BASE + 0x1011)
+#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR	(HFI_COMMON_BASE + 0x1012)
 
 #define HFI_EVENT_SYS_ERROR				(HFI_COMMON_BASE + 0x1)
 #define HFI_EVENT_SESSION_ERROR			(HFI_COMMON_BASE + 0x2)
@@ -80,6 +85,7 @@
 #define HFI_VIDEO_CODEC_SPARK				0x00000200
 #define HFI_VIDEO_CODEC_VP8				0x00001000
 #define HFI_VIDEO_CODEC_HEVC				0x00002000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID			0x00004000
 
 #define HFI_H264_PROFILE_BASELINE			0x00000001
 #define HFI_H264_PROFILE_MAIN				0x00000002
@@ -843,6 +849,12 @@
 	u32 rg_ext_event_data[1];
 };
 
+struct hfi_msg_release_buffer_ref_event_packet {
+	u8 *packet_buffer;
+	u8 *exra_data_buffer;
+	u32 output_tag;
+};
+
 struct hfi_msg_sys_init_done_packet {
 	u32 size;
 	u32 packet_type;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 317c6a9..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},
@@ -1451,23 +1453,23 @@
 		dev_err(dev, "Looking up %s property in node %s failed",
 			"qcom,cdc-dmic-sample-rate",
 			dev->of_node->full_name);
-		dmic_sample_rate = TAIKO_DMIC_SAMPLE_RATE_UNDEFINED;
+		dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
 	}
-	if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6HZ) {
-		if ((dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_2P4MHZ) &&
-		    (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_3P2MHZ) &&
-		    (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_4P8MHZ) &&
-		    (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_UNDEFINED)) {
+	if (pdata->mclk_rate == WCD9XXX_MCLK_CLK_9P6HZ) {
+		if ((dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ) &&
+		    (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ) &&
+		    (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ) &&
+		    (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED)) {
 			dev_err(dev, "Invalid dmic rate %d for mclk %d\n",
 				dmic_sample_rate, pdata->mclk_rate);
 			ret = -EINVAL;
 			goto err;
 		}
-	} else if (pdata->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ) {
-		if ((dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_3P072MHZ) &&
-		    (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_4P096MHZ) &&
-		    (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_6P144MHZ) &&
-		    (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_UNDEFINED)) {
+	} else if (pdata->mclk_rate == WCD9XXX_MCLK_CLK_12P288MHZ) {
+		if ((dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ) &&
+		    (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ) &&
+		    (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ) &&
+		    (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED)) {
 			dev_err(dev, "Invalid dmic rate %d for mclk %d\n",
 				dmic_sample_rate, pdata->mclk_rate);
 			ret = -EINVAL;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 58703cf..a30607c 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -314,7 +314,6 @@
 		return ret;
 	}
 	data->listener.id = 0;
-	data->type = QSEECOM_LISTENER_SERVICE;
 	if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
 		pr_err("Service is not unique and is already registered\n");
 		data->released = true;
@@ -432,9 +431,15 @@
 	uint32_t len;
 
 	/* Copy the relevant information needed for loading the image */
-	if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
+	if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
 		return -EFAULT;
 
+	if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
+					(req.sb_len == 0)) {
+		pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
+			req.ifd_data_fd, req.sb_len, req.virt_sb_base);
+		return -EFAULT;
+	}
 	/* Get the handle of the shared fd */
 	data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
 						req.ifd_data_fd);
@@ -605,7 +610,7 @@
 	struct qseecom_load_app_ireq load_req;
 
 	/* Copy the relevant information needed for loading the image */
-	if (__copy_from_user(&load_img_req,
+	if (copy_from_user(&load_img_req,
 				(void __user *)argp,
 				sizeof(struct qseecom_load_img_req))) {
 		pr_err("copy_from_user failed\n");
@@ -616,6 +621,7 @@
 	if (ret)
 		pr_warning("Unable to vote for SFPB clock");
 	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+	load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
 	memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
 
 	ret = __qseecom_check_app_exists(req);
@@ -876,7 +882,7 @@
 	struct qseecom_send_svc_cmd_req req;
 	/*struct qseecom_command_scm_resp resp;*/
 
-	if (__copy_from_user(&req,
+	if (copy_from_user(&req,
 				(void __user *)argp,
 				sizeof(req))) {
 		pr_err("copy_from_user failed\n");
@@ -888,8 +894,6 @@
 		return -EINVAL;
 	}
 
-	data->type = QSEECOM_SECURE_SERVICE;
-
 	switch (req.cmd_id) {
 	case QSEOS_RPMB_PROVISION_KEY_COMMAND:
 	case QSEOS_RPMB_ERASE_COMMAND:
@@ -901,6 +905,18 @@
 		pr_err("Unsupported cmd_id %d\n", req.cmd_id);
 		return -EINVAL;
 	}
+
+	ret = qsee_vote_for_clock(data, CLK_DFAB);
+	if (ret) {
+		pr_err("Failed to vote for DFAB clock%d\n", ret);
+		return ret;
+	}
+	ret = qsee_vote_for_clock(data, CLK_SFPB);
+	if (ret) {
+		pr_err("Failed to vote for SFPB clock%d\n", ret);
+		goto exit_reset_dfab_freq;
+	}
+
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
 				data->client.sb_virt, data->client.sb_length,
 				ION_IOC_CLEAN_INV_CACHES);
@@ -912,7 +928,7 @@
 				ION_IOC_INV_CACHES);
 	if (ret) {
 		pr_err("qseecom_scm_call failed with err: %d\n", ret);
-		return ret;
+		goto exit_reset_sdfab_freq;
 	}
 
 	switch (resp.result) {
@@ -935,8 +951,11 @@
 		ret = -EINVAL;
 		break;
 	}
+exit_reset_sdfab_freq:
+	qsee_disable_clock_vote(data, CLK_SFPB);
+exit_reset_dfab_freq:
+	qsee_disable_clock_vote(data, CLK_DFAB);
 	return ret;
-
 }
 
 static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
@@ -951,9 +970,22 @@
 		pr_err("cmd buffer or response buffer is null\n");
 		return -EINVAL;
 	}
+	if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
+		((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
+					data->client.sb_length))) {
+		pr_err("cmd buffer address not within shared bufffer\n");
+		return -EINVAL;
+	}
 
-	if (req->cmd_req_len <= 0 ||
-		req->resp_len <= 0 ||
+
+	if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base)  ||
+		((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
+					data->client.sb_length))){
+		pr_err("response buffer address not within shared bufffer\n");
+		return -EINVAL;
+	}
+
+	if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
 		req->cmd_req_len > data->client.sb_length ||
 		req->resp_len > data->client.sb_length) {
 		pr_err("cmd buffer length or "
@@ -961,6 +993,11 @@
 		return -EINVAL;
 	}
 
+	if (req->cmd_req_len > UINT_MAX - req->resp_len) {
+		pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
+		return -EINVAL;
+	}
+
 	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
 	if (reqd_len_sb_in > data->client.sb_length) {
 		pr_debug("Not enough memory to fit cmd_buf and "
@@ -980,7 +1017,7 @@
 
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
 					data->client.sb_virt,
-					(req->cmd_req_len + req->resp_len),
+					reqd_len_sb_in,
 					ION_IOC_CLEAN_INV_CACHES);
 
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
@@ -1186,6 +1223,7 @@
 					void __user *argp)
 {
 	int ret = 0;
+	int i;
 	struct qseecom_send_modfd_cmd_req req;
 	struct qseecom_send_cmd_req send_cmd_req;
 
@@ -1199,6 +1237,14 @@
 	send_cmd_req.resp_buf = req.resp_buf;
 	send_cmd_req.resp_len = req.resp_len;
 
+	/* validate offsets */
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
+			pr_err("Invalid offset %d = 0x%x\n",
+				i, req.ifd_data[i].cmd_buf_offset);
+			return -EINVAL;
+		}
+	}
 	ret = __qseecom_update_cmd_buf(&req, false, data, false);
 	if (ret)
 		return ret;
@@ -1789,11 +1835,20 @@
 						void __user *argp)
 {
 	struct qseecom_send_modfd_listener_resp resp;
+	int i;
 
 	if (copy_from_user(&resp, argp, sizeof(resp))) {
 		pr_err("copy_from_user failed");
 		return -EINVAL;
 	}
+	/* validate offsets */
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
+			pr_err("Invalid offset %d = 0x%x\n",
+				i, resp.ifd_data[i].cmd_buf_offset);
+			return -EINVAL;
+		}
+	}
 	__qseecom_update_cmd_buf(&resp, false, data, true);
 	qseecom.send_resp_flag = 1;
 	wake_up_interruptible(&qseecom.send_resp_wq);
@@ -2072,7 +2127,7 @@
 	struct qseecom_command_scm_resp resp;
 
 	/* Copy the relevant information needed for loading the image */
-	if (__copy_from_user(&load_img_req,
+	if (copy_from_user(&load_img_req,
 				(void __user *)argp,
 				sizeof(struct qseecom_load_img_req))) {
 		pr_err("copy_from_user failed\n");
@@ -2234,7 +2289,7 @@
 	unsigned long flags = 0;
 
 	/* Copy the relevant information needed for loading the image */
-	if (__copy_from_user(&query_req,
+	if (copy_from_user(&query_req,
 				(void __user *)argp,
 				sizeof(struct qseecom_qseos_app_load_query))) {
 		pr_err("copy_from_user failed\n");
@@ -2242,6 +2297,7 @@
 	}
 
 	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+	query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
 	memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
 
 	ret = __qseecom_check_app_exists(req);
@@ -2663,8 +2719,15 @@
 
 	switch (cmd) {
 	case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("reg lstnr req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
 		pr_debug("ioctl register_listener_req()\n");
 		atomic_inc(&data->ioctl_count);
+		data->type = QSEECOM_LISTENER_SERVICE;
 		ret = qseecom_register_listener(data, argp);
 		atomic_dec(&data->ioctl_count);
 		wake_up_all(&data->abort_wq);
@@ -2673,6 +2736,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
+		if ((data->listener.id == 0) ||
+			(data->type != QSEECOM_LISTENER_SERVICE)) {
+			pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
+						data->type, data->listener.id);
+			ret = -EINVAL;
+			break;
+		}
 		pr_debug("ioctl unregister_listener_req()\n");
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_unregister_listener(data);
@@ -2683,6 +2753,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_CMD_REQ: {
+		if ((data->client.app_id == 0) ||
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
 		/* Only one client allowed here at a time */
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
@@ -2695,6 +2772,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+		if ((data->client.app_id == 0) ||
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
 		/* Only one client allowed here at a time */
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
@@ -2707,6 +2791,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_RECEIVE_REQ: {
+		if ((data->listener.id == 0) ||
+			(data->type != QSEECOM_LISTENER_SERVICE)) {
+			pr_err("receive req: invalid handle (%d), lid(%d)\n",
+						data->type, data->listener.id);
+			ret = -EINVAL;
+			break;
+		}
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_receive_req(data);
 		atomic_dec(&data->ioctl_count);
@@ -2716,6 +2807,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_RESP_REQ: {
+		if ((data->listener.id == 0) ||
+			(data->type != QSEECOM_LISTENER_SERVICE)) {
+			pr_err("send resp req: invalid handle (%d), lid(%d)\n",
+						data->type, data->listener.id);
+			ret = -EINVAL;
+			break;
+		}
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_send_resp();
 		atomic_dec(&data->ioctl_count);
@@ -2725,6 +2823,15 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
+		if ((data->type != QSEECOM_CLIENT_APP) &&
+			(data->type != QSEECOM_GENERIC) &&
+			(data->type != QSEECOM_SECURE_SERVICE)) {
+			pr_err("set mem param req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
 		ret = qseecom_set_client_mem_param(data, argp);
 		if (ret)
 			pr_err("failed Qqseecom_set_mem_param request: %d\n",
@@ -2732,6 +2839,15 @@
 		break;
 	}
 	case QSEECOM_IOCTL_LOAD_APP_REQ: {
+		if ((data->type != QSEECOM_GENERIC) &&
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("load app req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		data->type = QSEECOM_CLIENT_APP;
+		pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		if (qseecom.qsee_version > QSEEE_VERSION_00) {
@@ -2750,6 +2866,14 @@
 		break;
 	}
 	case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
+		if ((data->client.app_id == 0) ||
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
+		pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_unload_app(data);
@@ -2768,6 +2892,20 @@
 		break;
 	}
 	case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
+		if ((data->type != QSEECOM_GENERIC) &&
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("perf enable req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		if ((data->type == QSEECOM_CLIENT_APP) &&
+			(data->client.app_id == 0)) {
+			pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
 		atomic_inc(&data->ioctl_count);
 		ret = qsee_vote_for_clock(data, CLK_DFAB);
 		if (ret)
@@ -2779,13 +2917,34 @@
 		break;
 	}
 	case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
+		if ((data->type != QSEECOM_SECURE_SERVICE) &&
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("perf disable req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		if ((data->type == QSEECOM_CLIENT_APP) &&
+			(data->client.app_id == 0)) {
+			pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
 		atomic_inc(&data->ioctl_count);
-		qsee_disable_clock_vote(data, CLK_DFAB);
-		qsee_disable_clock_vote(data, CLK_SFPB);
+			qsee_disable_clock_vote(data, CLK_DFAB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
 	case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("load ext elf req: invalid client handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
 		data->released = true;
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
@@ -2797,6 +2956,12 @@
 		break;
 	}
 	case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
+		if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
+			pr_err("unload ext elf req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
 		data->released = true;
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
@@ -2808,16 +2973,25 @@
 		break;
 	}
 	case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
+		data->type = QSEECOM_CLIENT_APP;
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
+		pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
 		ret = qseecom_query_app_loaded(data, argp);
 		atomic_dec(&data->ioctl_count);
 		mutex_unlock(&app_access_lock);
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("send cmd svc req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		data->type = QSEECOM_SECURE_SERVICE;
 		if (qseecom.qsee_version < QSEE_VERSION_03) {
-			pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
+			pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
 				qseecom.qsee_version);
 			return -EINVAL;
 		}
@@ -2829,8 +3003,14 @@
 		break;
 	}
 	case QSEECOM_IOCTL_CREATE_KEY_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("create key req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
 		if (qseecom.qsee_version < QSEE_VERSION_05) {
-			pr_err("Create Key feature not supported in qsee version %u\n",
+			pr_err("Create Key feature unsupported: qsee ver %u\n",
 				qseecom.qsee_version);
 			return -EINVAL;
 		}
@@ -2846,8 +3026,14 @@
 		break;
 	}
 	case QSEECOM_IOCTL_WIPE_KEY_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("wipe key req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
 		if (qseecom.qsee_version < QSEE_VERSION_05) {
-			pr_err("Wipe Key feature not supported in qsee version %u\n",
+			pr_err("Wipe Key feature unsupported in qsee ver %u\n",
 				qseecom.qsee_version);
 			return -EINVAL;
 		}
@@ -2862,6 +3048,12 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("save part hash req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
 		data->released = true;
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
@@ -2871,6 +3063,12 @@
 		break;
 	}
 	case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("ES activated req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
 		data->released = true;
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
@@ -2880,6 +3078,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_MODFD_RESP: {
+		if ((data->listener.id == 0) ||
+			(data->type != QSEECOM_LISTENER_SERVICE)) {
+			pr_err("receive req: invalid handle (%d), lid(%d)\n",
+						data->type, data->listener.id);
+			ret = -EINVAL;
+			break;
+		}
 		/* Only one client allowed here at a time */
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_send_modfd_resp(data, argp);
@@ -2890,6 +3095,13 @@
 		break;
 	}
 	case QSEECOM_IOCTL_UNPROTECT_BUF: {
+		if ((data->listener.id == 0) ||
+			(data->type != QSEECOM_LISTENER_SERVICE)) {
+			pr_err("receive req: invalid handle (%d), lid(%d)\n",
+						data->type, data->listener.id);
+			ret = -EINVAL;
+			break;
+		}
 		/* Only one client allowed here at a time */
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_unprotect_buffer(argp);
@@ -2900,6 +3112,7 @@
 		break;
 	}
 	default:
+		pr_err("Invalid IOCTL: %d\n", cmd);
 		return -EINVAL;
 	}
 	return ret;
@@ -2931,7 +3144,8 @@
 	int ret = 0;
 
 	if (data->released == false) {
-		pr_warn("data->released == false\n");
+		pr_warn("data: released = false, type = %d, data = 0x%x\n",
+			data->type, (u32)data);
 		switch (data->type) {
 		case QSEECOM_LISTENER_SERVICE:
 			ret = qseecom_unregister_listener(data);
@@ -2942,10 +3156,8 @@
 		case QSEECOM_SECURE_SERVICE:
 		case QSEECOM_GENERIC:
 			ret = qseecom_unmap_ion_allocated_memory(data);
-			if (ret) {
+			if (ret)
 				pr_err("Close failed\n");
-				return ret;
-			}
 			break;
 		case QSEECOM_UNAVAILABLE_CLIENT_APP:
 			break;
@@ -3264,9 +3476,10 @@
 			}
 			rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
 							&resp, sizeof(resp));
-			if (rc) {
-				pr_err("Failed to send secapp region info %d\n",
-									rc);
+			if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
+				pr_err("send secapp reg fail %d resp.res %d\n",
+							rc, resp.result);
+				rc = -EINVAL;
 				goto err;
 			}
 		}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 6ef389c..e5315bd 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1384,15 +1384,25 @@
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct request_queue *q = mq->queue;
 	struct mmc_card *card = md->queue.card;
 	int ret = 0;
 
 	ret = mmc_flush_cache(card);
-	if (ret)
+	if (ret == -ETIMEDOUT) {
+		pr_info("%s: requeue flush request after timeout", __func__);
+		spin_lock_irq(q->queue_lock);
+		blk_requeue_request(q, req);
+		spin_unlock_irq(q->queue_lock);
+		ret = 0;
+		goto exit;
+	} else if (ret) {
+		pr_err("%s: notify flush error to upper layers", __func__);
 		ret = -EIO;
+	}
 
 	blk_end_request_all(req, ret);
-
+exit:
 	return ret ? 0 : 1;
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 91efb12..293033b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -60,7 +60,7 @@
 #define MMC_BKOPS_MAX_TIMEOUT	(30 * 1000) /* max time to wait in ms */
 
 /* Flushing a large amount of cached data may take a long time. */
-#define MMC_FLUSH_REQ_TIMEOUT_MS 30000 /* msec */
+#define MMC_FLUSH_REQ_TIMEOUT_MS 90000 /* msec */
 
 static struct workqueue_struct *workqueue;
 
@@ -2688,13 +2688,19 @@
 unsigned long mmc_get_max_frequency(struct mmc_host *host)
 {
 	unsigned long freq;
+	unsigned char timing;
 
 	if (host->ops && host->ops->get_max_frequency) {
 		freq = host->ops->get_max_frequency(host);
 		goto out;
 	}
 
-	switch (host->ios.timing) {
+	if (mmc_card_hs400(host->card))
+		timing = MMC_TIMING_MMC_HS400;
+	else
+		timing = host->ios.timing;
+
+	switch (timing) {
 	case MMC_TIMING_UHS_SDR50:
 		freq = UHS_SDR50_MAX_DTR;
 		break;
@@ -2707,6 +2713,9 @@
 	case MMC_TIMING_UHS_DDR50:
 		freq = UHS_DDR50_MAX_DTR;
 		break;
+	case MMC_TIMING_MMC_HS400:
+		freq = MMC_HS400_MAX_DTR;
+		break;
 	default:
 		mmc_host_clk_hold(host);
 		freq = host->ios.clock;
@@ -2747,6 +2756,9 @@
 	case MMC_TIMING_MMC_HS200:
 		freq = MMC_HIGH_52_MAX_DTR;
 		break;
+	case MMC_TIMING_MMC_HS400:
+		freq = MMC_HIGH_52_MAX_DTR;
+		break;
 	case MMC_TIMING_UHS_DDR50:
 		freq = UHS_DDR50_MAX_DTR / 2;
 		break;
@@ -3339,7 +3351,7 @@
 						EXT_CSD_FLUSH_CACHE, 1,
 						MMC_FLUSH_REQ_TIMEOUT_MS);
 		if (err == -ETIMEDOUT) {
-			pr_debug("%s: cache flush timeout\n",
+			pr_err("%s: cache flush timeout\n",
 					mmc_hostname(card->host));
 			rc = mmc_interrupt_hpi(card);
 			if (rc)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e1609cf..997e14b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1177,6 +1177,26 @@
 	return err;
 }
 
+int mmc_set_clock_bus_speed(struct mmc_card *card, unsigned long freq)
+{
+	int err;
+
+	if (freq < MMC_HS400_MAX_DTR) {
+		/*
+		 * Lower the clock and adjust the timing to be able
+		 * to switch to HighSpeed mode
+		 */
+		mmc_set_timing(card->host, MMC_TIMING_LEGACY);
+		mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
+
+		err = mmc_select_hs(card, &card->cached_ext_csd);
+	} else {
+		err = mmc_select_hs400(card, &card->cached_ext_csd);
+	}
+
+	return err;
+}
+
 /**
  * mmc_change_bus_speed() - Change MMC card bus frequency at runtime
  * @host: pointer to mmc host structure
@@ -1219,7 +1239,13 @@
 	if (*freq < host->f_min)
 		*freq = host->f_min;
 
-	mmc_set_clock(host, (unsigned int) (*freq));
+	if (mmc_card_hs400(card)) {
+		err = mmc_set_clock_bus_speed(card, *freq);
+		if (err)
+			goto out;
+	} else {
+		mmc_set_clock(host, (unsigned int) (*freq));
+	}
 
 	if ((mmc_card_hs400(card) || mmc_card_hs200(card))
 		&& card->host->ops->execute_tuning) {
@@ -1413,6 +1439,7 @@
 		err = mmc_get_ext_csd(card, &ext_csd);
 		if (err)
 			goto free_card;
+		memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
 		err = mmc_read_ext_csd(card, ext_csd);
 		if (err)
 			goto free_card;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index a7ce6ae..2c8598b 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2687,6 +2687,9 @@
 		goto vreg_deinit;
 	}
 
+	/* Unset HC_MODE_EN bit in HC_MODE register */
+	writel_relaxed(0, (msm_host->core_mem + CORE_HC_MODE));
+
 	/* Set SW_RST bit in POWER register (Offset 0x0) */
 	writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
 			CORE_SW_RST, msm_host->core_mem + CORE_POWER);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f9f3802..0cb0491 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_ACMD12_ERR),
+		sdhci_readw(host, SDHCI_AUTO_CMD_ERR),
 		sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
 	pr_info(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
 		sdhci_readl(host, SDHCI_CAPABILITIES),
@@ -118,6 +118,12 @@
 	pr_info(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
 		sdhci_readw(host, SDHCI_COMMAND),
 		sdhci_readl(host, SDHCI_MAX_CURRENT));
+	pr_info(DRIVER_NAME ": Resp 1:   0x%08x | Resp 0:   0x%08x\n",
+		sdhci_readl(host, SDHCI_RESPONSE + 0x4),
+		sdhci_readl(host, SDHCI_RESPONSE));
+	pr_info(DRIVER_NAME ": Resp 3:   0x%08x | Resp 2:   0x%08x\n",
+		sdhci_readl(host, SDHCI_RESPONSE + 0xC),
+		sdhci_readl(host, SDHCI_RESPONSE + 0x8));
 	pr_info(DRIVER_NAME ": Host ctl2: 0x%08x\n",
 		sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
@@ -278,7 +284,8 @@
 		SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
 		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
 		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
+			     SDHCI_INT_AUTO_CMD_ERR);
 
 	if (soft) {
 		/* force clock reconfiguration */
@@ -2440,6 +2447,7 @@
 
 static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 {
+	u16 auto_cmd_status;
 	BUG_ON(intmask == 0);
 
 	if (!host->cmd) {
@@ -2456,6 +2464,18 @@
 			SDHCI_INT_INDEX))
 		host->cmd->error = -EILSEQ;
 
+	if (intmask & SDHCI_INT_AUTO_CMD_ERR) {
+		auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_ERR);
+		if (auto_cmd_status & (SDHCI_AUTO_CMD12_NOT_EXEC |
+				       SDHCI_AUTO_CMD_INDEX_ERR |
+				       SDHCI_AUTO_CMD_ENDBIT_ERR))
+			host->cmd->error = -EIO;
+		else if (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT_ERR)
+			host->cmd->error = -ETIMEDOUT;
+		else if (auto_cmd_status & SDHCI_AUTO_CMD_CRC_ERR)
+			host->cmd->error = -EILSEQ;
+	}
+
 	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
 		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
 			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a3d8442..3db99c4 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -135,21 +135,29 @@
 #define  SDHCI_INT_DATA_CRC	0x00200000
 #define  SDHCI_INT_DATA_END_BIT	0x00400000
 #define  SDHCI_INT_BUS_POWER	0x00800000
-#define  SDHCI_INT_ACMD12ERR	0x01000000
+#define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
 #define  SDHCI_INT_ADMA_ERROR	0x02000000
 
 #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
 #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
 
 #define  SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
-		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \
+				 SDHCI_INT_AUTO_CMD_ERR)
+
 #define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
 		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
 		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
 		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
 #define SDHCI_INT_ALL_MASK	((unsigned int)-1)
 
-#define SDHCI_ACMD12_ERR	0x3C
+#define SDHCI_AUTO_CMD_ERR		0x3C
+#define SDHCI_AUTO_CMD12_NOT_EXEC	0x0001
+#define SDHCI_AUTO_CMD_TIMEOUT_ERR	0x0002
+#define SDHCI_AUTO_CMD_CRC_ERR		0x0004
+#define SDHCI_AUTO_CMD_ENDBIT_ERR	0x0008
+#define SDHCI_AUTO_CMD_INDEX_ERR	0x0010
+#define SDHCI_AUTO_CMD12_NOT_ISSUED	0x0080
 
 #define SDHCI_HOST_CONTROL2		0x3E
 #define  SDHCI_CTRL_UHS_MASK		0x0007
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 44f86dd..9f06258 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -42,6 +42,11 @@
 module_param_named(debug_enable, msm_rmnet_bam_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static unsigned long int msm_rmnet_bam_headroom_check_failure;
+module_param(msm_rmnet_bam_headroom_check_failure, ulong, S_IRUGO);
+MODULE_PARM_DESC(msm_rmnet_bam_headroom_check_failure,
+		 "Number of packets with insufficient headroom");
+
 #define DEBUG_MASK_LVL0 (1U << 0)
 #define DEBUG_MASK_LVL1 (1U << 1)
 #define DEBUG_MASK_LVL2 (1U << 2)
@@ -287,6 +292,23 @@
 			((struct net_device *)dev)->name, __func__);
 }
 
+static struct sk_buff *_rmnet_add_headroom(struct sk_buff **skb,
+					   struct net_device *dev)
+{
+	struct sk_buff *skbn;
+
+	if (skb_headroom(*skb) < dev->needed_headroom) {
+		msm_rmnet_bam_headroom_check_failure++;
+		skbn = skb_realloc_headroom(*skb, dev->needed_headroom);
+		kfree_skb(*skb);
+		*skb = skbn;
+	} else {
+		skbn = *skb;
+	}
+
+	return skbn;
+}
+
 static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
@@ -295,6 +317,10 @@
 	u32 opmode;
 	unsigned long flags;
 
+	if (unlikely(!_rmnet_add_headroom(&skb, dev))) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 	/* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
 	spin_lock_irqsave(&p->lock, flags);
 	opmode = p->operation_mode;
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 7d6e345..7b743a4 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/rwsem.h>
 #include <linux/mfd/pm8xxx/misc.h>
+#include <linux/qpnp/qpnp-adc.h>
 
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
@@ -97,6 +98,12 @@
 #define PRONTO_PMU_CBCR_OFFSET        0x0008
 #define PRONTO_PMU_CBCR_CLK_EN        BIT(0)
 
+#define PRONTO_PMU_COM_CPU_CBCR_OFFSET     0x0030
+#define PRONTO_PMU_COM_AHB_CBCR_OFFSET     0x0034
+#define PRONTO_PMU_CFG_OFFSET              0x1004
+#define PRONTO_PMU_COM_CSR_OFFSET          0x1040
+#define PRONTO_PMU_SOFT_RESET_OFFSET       0x104C
+
 #define MSM_PRONTO_A2XB_BASE		0xfb100400
 #define A2XB_CFG_OFFSET				0x00
 #define A2XB_INT_SRC_OFFSET			0x0c
@@ -131,6 +138,10 @@
 #define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
 
 #define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
+#define WCNSS_VBATT_THRESHOLD		3500000
+#define WCNSS_VBATT_GUARD		200
+#define WCNSS_VBATT_HIGH		3700000
+#define WCNSS_VBATT_LOW			3300000
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		(4*1024)
@@ -146,6 +157,7 @@
 #define	WCNSS_CALDATA_UPLD_RSP        (WCNSS_CTRL_MSG_START + 5)
 #define	WCNSS_CALDATA_DNLD_REQ        (WCNSS_CTRL_MSG_START + 6)
 #define	WCNSS_CALDATA_DNLD_RSP        (WCNSS_CTRL_MSG_START + 7)
+#define	WCNSS_VBATT_LEVEL_IND         (WCNSS_CTRL_MSG_START + 8)
 
 
 #define VALID_VERSION(version) \
@@ -277,6 +289,16 @@
 	struct cal_data_params cal_params;
 };
 
+struct vbatt_level {
+	u32 curr_volt;
+	u32 threshold;
+};
+
+struct vbatt_message {
+	struct smd_msg_hdr hdr;
+	struct vbatt_level vbatt;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -298,6 +320,7 @@
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
+	struct delayed_work vbatt_work;
 	struct work_struct wcnssctrl_version_work;
 	struct work_struct wcnssctrl_nvbin_dnld_work;
 	struct work_struct wcnssctrl_rx_work;
@@ -324,8 +347,12 @@
 	int	user_cal_exp_size;
 	int	device_opened;
 	int	iris_xo_mode_set;
+	int	fw_vbatt_state;
 	struct mutex dev_lock;
 	wait_queue_head_t read_wait;
+	struct qpnp_adc_tm_btm_param vbat_monitor_params;
+	struct qpnp_adc_tm_chip *adc_tm_dev;
+	struct mutex vbat_monitor_mutex;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -456,8 +483,34 @@
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
 
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CPU_CBCR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_AHB_CBCR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_CFG %08x\n", __func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CSR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_SOFT_RESET %08x\n",
+						__func__, reg);
+
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_GDSCR %08x\n",
+						__func__, reg);
 	reg >>= 31;
 
 	if (!reg) {
@@ -595,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)
 {
@@ -1081,7 +1142,6 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
 
-
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -1099,6 +1159,102 @@
 	return ret;
 }
 
+static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx)
+{
+	mutex_lock(&penv->vbat_monitor_mutex);
+	cancel_delayed_work_sync(&penv->vbatt_work);
+
+	if (state == ADC_TM_LOW_STATE) {
+		pr_debug("wcnss: low voltage notification triggered\n");
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_HIGH_THR_ENABLE;
+		penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD +
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.low_thr = 0;
+	} else if (state == ADC_TM_HIGH_STATE) {
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_LOW_THR_ENABLE;
+		penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD -
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.high_thr = 0;
+		pr_debug("wcnss: high voltage notification triggered\n");
+	} else {
+		pr_debug("wcnss: unknown voltage notification state: %d\n",
+				state);
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+			&penv->vbat_monitor_params);
+	schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000));
+	mutex_unlock(&penv->vbat_monitor_mutex);
+}
+
+static int wcnss_setup_vbat_monitoring(void)
+{
+	int rc = -1;
+
+	if (!penv->adc_tm_dev) {
+		pr_err("wcnss: not setting up vbatt\n");
+		return rc;
+	}
+	penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+	penv->vbat_monitor_params.channel = VBAT_SNS;
+	penv->vbat_monitor_params.btm_ctx = (void *)penv;
+	penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+	penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat;
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+					&penv->vbat_monitor_params);
+	if (rc)
+		pr_err("wcnss: tm setup failed: %d\n", rc);
+
+	return rc;
+}
+
+static void wcnss_update_vbatt(struct work_struct *work)
+{
+	struct vbatt_message vbatt_msg;
+	int ret = 0;
+
+	vbatt_msg.hdr.msg_type = WCNSS_VBATT_LEVEL_IND;
+	vbatt_msg.hdr.msg_len = sizeof(struct vbatt_message);
+	vbatt_msg.vbatt.threshold = WCNSS_VBATT_THRESHOLD;
+
+	mutex_lock(&penv->vbat_monitor_mutex);
+	if (penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_LOW ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) {
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH;
+		penv->fw_vbatt_state = WCNSS_VBATT_HIGH;
+		pr_debug("wcnss: send HIGH BATT to FW\n");
+	} else if (!penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_HIGH ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW;
+		penv->fw_vbatt_state = WCNSS_VBATT_LOW;
+		pr_debug("wcnss: send LOW BATT to FW\n");
+	} else {
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	mutex_unlock(&penv->vbat_monitor_mutex);
+	ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
+	if (ret < 0)
+		pr_err("wcnss: smd tx failed\n");
+	return;
+}
+
+
 static unsigned char wcnss_fw_status(void)
 {
 	int len = 0;
@@ -1312,6 +1468,7 @@
 		fw_status = wcnss_fw_status();
 		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
 			fw_status);
+		wcnss_setup_vbat_monitoring();
 		break;
 
 	case WCNSS_CALDATA_DNLD_RSP:
@@ -1791,6 +1948,14 @@
 		}
 
 	}
+	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
+	if (IS_ERR(penv->adc_tm_dev)) {
+		pr_err("%s:  adc get failed\n", __func__);
+		penv->adc_tm_dev = NULL;
+	} else {
+		INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt);
+		penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
+	}
 
 	/* trigger initialization of the WCNSS */
 	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
@@ -2005,6 +2170,7 @@
 	}
 
 	mutex_init(&penv->dev_lock);
+	mutex_init(&penv->vbat_monitor_mutex);
 	init_waitqueue_head(&penv->read_wait);
 
 	/* Since we were built into the kernel we'll be called as part
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 87c7c30..67b057c 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -26,12 +26,15 @@
 #include <linux/of_device.h>
 #include <linux/regulator/consumer.h>
 #include "nfc-nci.h"
+#include <mach/gpiomux.h>
 
 struct qca199x_platform_data {
 	unsigned int irq_gpio;
 	unsigned int dis_gpio;
 	unsigned int ven_gpio;
 	unsigned int reg;
+	const char *clk_src;
+	unsigned int clk_src_gpio;
 };
 
 static struct of_device_id msm_match_table[] = {
@@ -397,7 +400,9 @@
 		gpio_set_value(qca199x_dev->dis_gpio, 1);
 		usleep(1000);
 	} else if (arg == 2) {
+		mutex_lock(&qca199x_dev->read_mutex);
 		r = nfcc_initialise(qca199x_dev->client, 0xE);
+		mutex_unlock(&qca199x_dev->read_mutex);
 		if (r) {
 			dev_err(&qca199x_dev->client->dev,
 					"nfc-nci probe: request nfcc initialise failed\n");
@@ -419,7 +424,6 @@
 	return r;
 }
 
-
 /*
  * Inside nfc_ioctl_nfcc_mode
  *
@@ -477,6 +481,64 @@
 }
 
 /*
+ * Inside nfc_ioctl_nfcc_version
+ *
+ * @brief   nfc_ioctl_nfcc_version
+ *
+ *
+ */
+int nfc_ioctl_nfcc_version(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	int r = 0;
+	unsigned short	slave_addr	=	0xE;
+	unsigned short	curr_addr;
+
+	unsigned char raw_chip_version_addr		= 0x00;
+	unsigned char raw_chip_rev_id_addr		= 0x9C;
+	unsigned char raw_chip_version			= 0xFF;
+
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	struct qca199x_platform_data *platform_data;
+
+	platform_data = qca199x_dev->client->dev.platform_data;
+
+	if (arg == 0) {
+		curr_addr = qca199x_dev->client->addr;
+		qca199x_dev->client->addr = slave_addr;
+		r = nfc_i2c_write(qca199x_dev->client,
+				&raw_chip_version_addr, 1);
+		if (r < 0)
+			goto invalid_wr;
+		usleep(10);
+		r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
+		/* Restore original NFCC slave I2C address */
+		qca199x_dev->client->addr = curr_addr;
+	}
+	if (arg == 1) {
+		curr_addr = qca199x_dev->client->addr;
+		qca199x_dev->client->addr = slave_addr;
+		r = nfc_i2c_write(qca199x_dev->client,
+				&raw_chip_rev_id_addr, 1);
+		if (r < 0)
+			goto invalid_wr;
+		usleep(10);
+		r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
+		/* Restore original NFCC slave I2C address */
+		qca199x_dev->client->addr = curr_addr;
+	}
+
+	return raw_chip_version;
+invalid_wr:
+	raw_chip_version = 0xFF;
+	dev_err(&qca199x_dev->client->dev,
+			"\nNFCC_INVALID_CHIP_VERSION = %d\n", raw_chip_version);
+	return raw_chip_version;
+}
+
+
+
+/*
  * Inside nfc_ioctl_kernel_logging
  *
  * @brief   nfc_ioctl_kernel_logging
@@ -522,6 +584,9 @@
 	case NFCC_MODE:
 		nfc_ioctl_nfcc_mode(pfile, cmd, arg);
 		break;
+	case NFCC_VERSION:
+		r = nfc_ioctl_nfcc_version(pfile, cmd, arg);
+		break;
 	case NFC_KERNEL_LOGGING_MODE:
 		nfc_ioctl_kernel_logging(arg, pfile);
 		break;
@@ -690,6 +755,14 @@
 	if ((!gpio_is_valid(pdata->irq_gpio)))
 		return -EINVAL;
 
+	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src);
+
+	if (!strcmp(pdata->clk_src, "GPCLK"))
+		pdata->clk_src_gpio = of_get_named_gpio(np,
+				"qcom,clk-en-gpio", 0);
+
+	if (r)
+		return -EINVAL;
 	return r;
 }
 
@@ -698,7 +771,7 @@
 {
 	int r = 0;
 	int irqn = 0;
-	struct clk *nfc_clk;
+	struct clk *nfc_clk = NULL;
 	struct device_node *node = client->dev.of_node;
 	struct qca199x_platform_data *platform_data;
 	struct qca199x_dev *qca199x_dev;
@@ -769,7 +842,7 @@
 			dev_err(&client->dev,
 			"NFC: unable to request gpio [%d]\n",
 				platform_data->dis_gpio);
-			goto err_dis_gpio;
+			goto err_free_dev;
 		}
 		r = gpio_direction_output(platform_data->dis_gpio, 1);
 		if (r) {
@@ -785,15 +858,28 @@
 	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
 	msleep(20);
 	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
-
-	nfc_clk  = clk_get(&client->dev, "ref_clk");
-
-	if (nfc_clk == NULL)
-		goto err_dis_gpio;
-
+	if (!strcmp(platform_data->clk_src, "BBCLK2")) {
+		nfc_clk  = clk_get(&client->dev, "ref_clk");
+		if (nfc_clk == NULL)
+			goto err_dis_gpio;
+	} else if (!strcmp(platform_data->clk_src, "RFCLK3")) {
+		nfc_clk  = clk_get(&client->dev, "ref_clk_rf");
+		if (nfc_clk == NULL)
+			goto err_dis_gpio;
+	} else if (!strcmp(platform_data->clk_src, "GPCLK")) {
+		if (gpio_is_valid(platform_data->clk_src_gpio)) {
+			nfc_clk  = clk_get(&client->dev, "core_clk");
+			if (nfc_clk == NULL)
+				goto err_dis_gpio;
+		} else {
+			goto err_dis_gpio;
+		}
+	} else {
+		nfc_clk = NULL;
+	}
 	r = clk_prepare_enable(nfc_clk);
 	if (r)
-		goto err_dis_gpio;
+		goto err_clk;
 
 	platform_data->ven_gpio = of_get_named_gpio(node,
 						"qcom,clk-gpio", 0);
@@ -813,11 +899,9 @@
 						platform_data->ven_gpio);
 			goto err_ven_gpio;
 		}
-
 	} else {
-
 		dev_err(&client->dev, "ven gpio not provided\n");
-		goto err_dis_gpio;
+		goto err_clk;
 	}
 	qca199x_dev->dis_gpio = platform_data->dis_gpio;
 	qca199x_dev->irq_gpio = platform_data->irq_gpio;
@@ -871,7 +955,18 @@
 	mutex_destroy(&qca199x_dev->read_mutex);
 err_ven_gpio:
 	gpio_free(platform_data->ven_gpio);
+err_clk:
+	clk_disable_unprepare(nfc_clk);
 err_dis_gpio:
+	r = gpio_direction_input(platform_data->dis_gpio);
+	if (r)
+		dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
+	if (!strcmp(platform_data->clk_src, "GPCLK")) {
+		r = gpio_direction_input(platform_data->clk_src_gpio);
+		if (r)
+			dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
+		gpio_free(platform_data->clk_src_gpio);
+	}
 	gpio_free(platform_data->dis_gpio);
 err_irq:
 	gpio_free(platform_data->irq_gpio);
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index c3cabc2..81f2521 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -49,26 +49,27 @@
 	enum ehandler_mode	handle_flavour;
 } tdevicemode;
 
-#define NFC_DRIVER_NAME			"nfc-nci"
+#define NFC_DRIVER_NAME		"nfc-nci"
 #define NFC_I2C_DRIVER_NAME		"NCI NFC I2C Interface",
 
-#define NCI_I2C_SLAVE			(0x2C)
-#define NFC_I2C_BUS			3	/* 6, 10, 4, 5 */
-#define NFC_SET_PWR			_IOW(0xE9, 0x01, unsigned int)
-#define NFCC_MODE			_IOW(0xE9, 0x02, unsigned int)
+#define NCI_I2C_SLAVE	(0x2C)
+#define NFC_I2C_BUS	3	/* 6, 10, 4, 5 */
+#define NFC_SET_PWR	_IOW(0xE9, 0x01, unsigned int)
+#define NFCC_MODE	_IOW(0xE9, 0x02, unsigned int)
 #define NFC_KERNEL_LOGGING_MODE		_IOW(0xE9, 0x03, unsigned int)
-#define SET_RX_BLOCK			_IOW(0xE9, 0x04, unsigned int)
+#define SET_RX_BLOCK	_IOW(0xE9, 0x04, unsigned int)
 #define SET_EMULATOR_TEST_POINT		_IOW(0xE9, 0x05, unsigned int)
+#define NFCC_VERSION				_IOW(0xE9, 0x08, unsigned int)
 
-#define NFC_MAX_I2C_TRANSFER		(0x0400)
-#define NFC_MSG_MAX_SIZE		(0x21)
+#define NFC_MAX_I2C_TRANSFER	(0x0400)
+#define NFC_MSG_MAX_SIZE	(0x21)
 
 #define NFC_RX_BUFFER_CNT_START		(0x0)
 
-#define NFC_RX_BUFFER_BLOCK_SIZE	(0x120)		/* Bytes per Block */
+#define NFC_RX_BUFFER_BLOCK_SIZE	(0x120)	/* Bytes per Block */
 #define NFC_RX_BUFFER_PAGE_SIZE		(0x1000)	/* Page size Bytes */
 #define NFC_RX_BUFFER_PAGES		(0x8)
-#define NFC_RX_ORDER_FREE_PAGES		(0x3)		/* Free 8 Pages */
+#define NFC_RX_ORDER_FREE_PAGES	(0x3)	/* Free 8 Pages */
 
 /* The total no. of Blocks */
 #define NFC_RX_BUFFER_CNT_LIMIT		(unsigned short)(	\
@@ -86,10 +87,10 @@
 
 /** Power Management Related **/
 
-#define NFCC_WAKE			(0x01)
-#define NFCC_SLEEP			(0x00)
+#define NFCC_WAKE				(0x01)
+#define NFCC_SLEEP				(0x00)
 
-#define XTAL_CLOCK			(0X00)
+#define XTAL_CLOCK				(0X00)
 #define REFERENCE_CLOCK			(0X01)
 
 /* LDO Trim Settings */
@@ -122,8 +123,8 @@
 #define LOCALBIASXTAL	(0x20)
 #define BIAS2X_FORCE	(0x10)
 #define BIAS2X		(0x08)
-#define LBIAS2X		(0x04)
-#define SMALLRF		(0x02)
+#define LBIAS2X	(0x04)
+#define SMALLRF	(0x02)
 #define SMALLRBIAS	(0x01)
 
 /* Select as appropriate */
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index b4edce8..c0371a5 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1031,8 +1031,11 @@
 	index = ffs(pon_sts);
 	if ((index > PON_REASON_MAX) || (index < 0))
 		index = 0;
-	pr_info("PMIC@SID%d Power-on reason: %s\n", pon->spmi->sid,
-			index ? qpnp_pon_reason[index - 1] : "Unknown");
+
+	cold_boot = !qpnp_pon_is_warm_reset();
+	pr_info("PMIC@SID%d Power-on reason: %s and '%s' boot\n",
+		pon->spmi->sid, index ? qpnp_pon_reason[index - 1] :
+		"Unknown", cold_boot ? "cold" : "warm");
 
 	rc = of_property_read_u32(pon->spmi->dev.of_node,
 				"qcom,pon-dbc-delay", &delay);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 61f4946..97e952e 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -98,6 +98,23 @@
 }
 EXPORT_SYMBOL_GPL(power_supply_set_online);
 
+
+/** power_supply_set_health_state - set health state of the power supply
+ * @psy:       the power supply to control
+ * @health:    sets health property of power supply
+ */
+int power_supply_set_health_state(struct power_supply *psy, int health)
+{
+	const union power_supply_propval ret = {health,};
+
+	if (psy->set_property)
+		return psy->set_property(psy, POWER_SUPPLY_PROP_HEALTH,
+		&ret);
+	return -ENXIO;
+}
+EXPORT_SYMBOL(power_supply_set_health_state);
+
+
 /**
  * power_supply_set_scope - set scope of the power supply
  * @psy:	the power supply to control
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 02fd276..319a24d 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -150,6 +150,7 @@
 	POWER_SUPPLY_ATTR(input_voltage_regulation),
 	POWER_SUPPLY_ATTR(current_max),
 	POWER_SUPPLY_ATTR(input_current_max),
+	POWER_SUPPLY_ATTR(input_current_trim),
 	POWER_SUPPLY_ATTR(current_now),
 	POWER_SUPPLY_ATTR(current_avg),
 	POWER_SUPPLY_ATTR(power_now),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 6706e0d..ad39e88 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -80,8 +80,7 @@
 
 /* Configuration for saving of shutdown soc/iavg */
 #define IGNORE_SOC_TEMP_DECIDEG		50
-#define IAVG_STEP_SIZE_MA		50
-#define IAVG_START			600
+#define IAVG_STEP_SIZE_MA		10
 #define IAVG_INVALID			0xFF
 #define SOC_INVALID			0x7E
 
@@ -190,6 +189,7 @@
 	struct mutex			vbat_monitor_mutex;
 	struct mutex			soc_invalidation_mutex;
 	struct mutex			last_soc_mutex;
+	struct mutex			status_lock;
 
 	bool				use_external_rsense;
 	bool				use_ocv_thresholds;
@@ -295,6 +295,7 @@
 
 static enum power_supply_property msm_bms_power_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
@@ -1232,7 +1233,6 @@
 }
 
 #define MIN_IAVG_MA 250
-#define MIN_SECONDS_FOR_VALID_SAMPLE	20
 static int calculate_unusable_charge_uah(struct qpnp_bms_chip *chip,
 					struct soc_params *params,
 					int batt_temp)
@@ -1256,17 +1256,19 @@
 		chip->iavg_num_samples = IAVG_SAMPLES;
 	}
 
-	/*
-	 * if charging use a nominal avg current to keep
-	 * a reasonable UUC while charging
-	 */
-	if (uuc_iavg_ma < MIN_IAVG_MA)
-		uuc_iavg_ma = MIN_IAVG_MA;
-	chip->iavg_samples_ma[chip->iavg_index] = uuc_iavg_ma;
-	chip->iavg_index = (chip->iavg_index + 1) % IAVG_SAMPLES;
-	chip->iavg_num_samples++;
-	if (chip->iavg_num_samples >= IAVG_SAMPLES)
-		chip->iavg_num_samples = IAVG_SAMPLES;
+	if (params->delta_time_s >= IAVG_MINIMAL_TIME) {
+		/*
+		* if charging use a nominal avg current to keep
+		* a reasonable UUC while charging
+		*/
+		if (uuc_iavg_ma < MIN_IAVG_MA)
+			uuc_iavg_ma = MIN_IAVG_MA;
+		chip->iavg_samples_ma[chip->iavg_index] = uuc_iavg_ma;
+		chip->iavg_index = (chip->iavg_index + 1) % IAVG_SAMPLES;
+		chip->iavg_num_samples++;
+		if (chip->iavg_num_samples >= IAVG_SAMPLES)
+			chip->iavg_num_samples = IAVG_SAMPLES;
+	}
 
 	/* now that this sample is added calcualte the average */
 	uuc_iavg_ma = 0;
@@ -1297,7 +1299,6 @@
 	uuc_uah_iavg = adjust_uuc(chip, params, pc_unusable,
 					uuc_uah_iavg, batt_temp);
 
-	chip->first_time_calc_uuc = 0;
 	return uuc_uah_iavg;
 }
 
@@ -1606,8 +1607,8 @@
 	int rc;
 	int iavg_ma = chip->prev_uuc_iavg_ma;
 
-	if (iavg_ma > IAVG_START)
-		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+	if (iavg_ma > MIN_IAVG_MA)
+		temp = (iavg_ma - MIN_IAVG_MA) / IAVG_STEP_SIZE_MA;
 	else
 		temp = 0;
 
@@ -2331,6 +2332,7 @@
 
 	get_current_time(&chip->last_recalc_time);
 	chip->first_time_calc_soc = 0;
+	chip->first_time_calc_uuc = 0;
 	return chip->calculated_soc;
 }
 
@@ -2685,7 +2687,8 @@
 		return;
 	}
 
-	temp = kzalloc(sizeof(struct single_row_lut), GFP_KERNEL);
+	temp = devm_kzalloc(chip->dev, sizeof(struct single_row_lut),
+			GFP_KERNEL);
 	if (!temp) {
 		pr_err("Cannot allocate memory for adjusted fcc table\n");
 		return;
@@ -2703,7 +2706,7 @@
 
 	old = chip->adjusted_fcc_temp_lut;
 	chip->adjusted_fcc_temp_lut = temp;
-	kfree(old);
+	devm_kfree(chip->dev, old);
 }
 
 static int read_fcc_data_from_backup(struct qpnp_bms_chip *chip)
@@ -3110,6 +3113,7 @@
 {
 	int status = get_battery_status(chip);
 
+	mutex_lock(&chip->status_lock);
 	if (chip->battery_status != status) {
 		pr_debug("status = %d, shadow status = %d\n",
 				status, chip->battery_status);
@@ -3126,6 +3130,7 @@
 			pr_debug("battery full\n");
 			enable_bms_irq(&chip->ocv_thr_irq);
 			enable_bms_irq(&chip->sw_cc_thr_irq);
+			recalculate_soc(chip);
 		} else if (chip->battery_status
 				== POWER_SUPPLY_STATUS_FULL) {
 			pr_debug("battery not full any more\n");
@@ -3138,6 +3143,7 @@
 		 * recalculation to update the SoC */
 		schedule_work(&chip->recalc_work);
 	}
+	mutex_unlock(&chip->status_lock);
 }
 
 #define CALIB_WRKARND_DIG_MAJOR_MAX		0x03
@@ -3212,6 +3218,9 @@
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_bms_capacity(chip);
 		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = chip->battery_status;
+		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		val->intval = get_prop_bms_current_now(chip);
 		break;
@@ -3285,17 +3294,17 @@
 	if (rc) {
 		pr_err("failed to read addr = %d %d assuming %d\n",
 				chip->base + IAVG_STORAGE_REG, rc,
-				IAVG_START);
-		return IAVG_START;
+				MIN_IAVG_MA);
+		return MIN_IAVG_MA;
 	} else if (iavg == IAVG_INVALID) {
 		pr_err("invalid iavg read from BMS1_DATA_REG_1, using %d\n",
-				IAVG_START);
-		return IAVG_START;
+				MIN_IAVG_MA);
+		return MIN_IAVG_MA;
 	} else {
 		if (iavg == 0)
-			return IAVG_START;
+			return MIN_IAVG_MA;
 		else
-			return IAVG_START + IAVG_STEP_SIZE_MA * (iavg + 1);
+			return MIN_IAVG_MA + IAVG_STEP_SIZE_MA * iavg;
 	}
 }
 
@@ -3434,7 +3443,7 @@
 static int set_battery_data(struct qpnp_bms_chip *chip)
 {
 	int64_t battery_id;
-	int rc, dt_data = false;
+	int rc = 0, dt_data = false;
 	struct bms_battery_data *batt_data;
 	struct device_node *node;
 
@@ -3458,41 +3467,52 @@
 
 		node = of_find_node_by_name(chip->spmi->dev.of_node,
 				"qcom,battery-data");
-		if (node) {
-			batt_data = kzalloc(sizeof(struct bms_battery_data),
-					GFP_KERNEL);
-			batt_data->fcc_temp_lut = kzalloc(
-					sizeof(struct single_row_lut),
-					GFP_KERNEL);
-			batt_data->pc_temp_ocv_lut = kzalloc(
-					sizeof(struct pc_temp_ocv_lut),
-					GFP_KERNEL);
-			batt_data->rbatt_sf_lut = kzalloc(
-					sizeof(struct sf_lut), GFP_KERNEL);
+		if (!node) {
+			pr_warn("No available batterydata, using palladium 1500\n");
+			batt_data = &palladium_1500_data;
+			goto assign_data;
+		}
+		batt_data = devm_kzalloc(chip->dev,
+				sizeof(struct bms_battery_data), GFP_KERNEL);
+		if (!batt_data) {
+			pr_err("Could not alloc battery data\n");
+			batt_data = &palladium_1500_data;
+			goto assign_data;
+		}
+		batt_data->fcc_temp_lut = devm_kzalloc(chip->dev,
+				sizeof(struct single_row_lut),
+				GFP_KERNEL);
+		batt_data->pc_temp_ocv_lut = devm_kzalloc(chip->dev,
+				sizeof(struct pc_temp_ocv_lut),
+				GFP_KERNEL);
+		batt_data->rbatt_sf_lut = devm_kzalloc(chip->dev,
+				sizeof(struct sf_lut),
+				GFP_KERNEL);
 
-			batt_data->max_voltage_uv = -1;
-			batt_data->cutoff_uv = -1;
-			batt_data->iterm_ua = -1;
+		batt_data->max_voltage_uv = -1;
+		batt_data->cutoff_uv = -1;
+		batt_data->iterm_ua = -1;
 
-			rc = of_batterydata_read_data(node,
-					batt_data, battery_id);
-			if (rc) {
-				pr_err("battery data load failed, using palladium 1500\n");
-				kfree(batt_data->fcc_temp_lut);
-				kfree(batt_data->pc_temp_ocv_lut);
-				kfree(batt_data->rbatt_sf_lut);
-				kfree(batt_data);
-				batt_data = &palladium_1500_data;
-			} else {
-				dt_data = true;
-			}
+		/*
+		 * if the alloced luts are 0s, of_batterydata_read_data ignores
+		 * them.
+		 */
+		rc = of_batterydata_read_data(node, batt_data, battery_id);
+		if (rc == 0 && batt_data->fcc_temp_lut
+				&& batt_data->pc_temp_ocv_lut
+				&& batt_data->rbatt_sf_lut) {
+			dt_data = true;
 		} else {
-			pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
-					battery_id);
+			pr_err("battery data load failed, using palladium 1500\n");
+			devm_kfree(chip->dev, batt_data->fcc_temp_lut);
+			devm_kfree(chip->dev, batt_data->pc_temp_ocv_lut);
+			devm_kfree(chip->dev, batt_data->rbatt_sf_lut);
+			devm_kfree(chip->dev, batt_data);
 			batt_data = &palladium_1500_data;
 		}
 	}
 
+assign_data:
 	chip->fcc_mah = batt_data->fcc;
 	chip->fcc_temp_lut = batt_data->fcc_temp_lut;
 	chip->fcc_sf_lut = batt_data->fcc_sf_lut;
@@ -3511,13 +3531,20 @@
 	if (batt_data->iterm_ua >= 0 && dt_data)
 		chip->chg_term_ua = batt_data->iterm_ua;
 
-	if (dt_data)
-		kfree(batt_data);
-
 	if (chip->pc_temp_ocv_lut == NULL) {
-		pr_err("temp ocv lut table is NULL\n");
+		pr_err("temp ocv lut table has not been loaded\n");
+		if (dt_data) {
+			devm_kfree(chip->dev, batt_data->fcc_temp_lut);
+			devm_kfree(chip->dev, batt_data->pc_temp_ocv_lut);
+			devm_kfree(chip->dev, batt_data->rbatt_sf_lut);
+			devm_kfree(chip->dev, batt_data);
+		}
 		return -EINVAL;
 	}
+
+	if (dt_data)
+		devm_kfree(chip->dev, batt_data);
+
 	return 0;
 }
 
@@ -3634,6 +3661,8 @@
 		chip->fcc_learning_samples = devm_kzalloc(&chip->spmi->dev,
 				(sizeof(struct fcc_sample) *
 				chip->min_fcc_learning_samples), GFP_KERNEL);
+		if (chip->fcc_learning_samples == NULL)
+			return -ENOMEM;
 		pr_debug("min-fcc-soc=%d, min-fcc-pc=%d, min-fcc-cycles=%d\n",
 			chip->min_fcc_learning_soc, chip->min_fcc_ocv_pc,
 			chip->min_fcc_learning_samples);
@@ -3973,7 +4002,8 @@
 	bool warm_reset;
 	int rc, vbatt;
 
-	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	chip = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_bms_chip),
+			GFP_KERNEL);
 
 	if (chip == NULL) {
 		pr_err("kzalloc() failed.\n");
@@ -3989,6 +4019,7 @@
 	mutex_init(&chip->vbat_monitor_mutex);
 	mutex_init(&chip->soc_invalidation_mutex);
 	mutex_init(&chip->last_soc_mutex);
+	mutex_init(&chip->status_lock);
 	init_waitqueue_head(&chip->bms_wait_queue);
 
 	warm_reset = qpnp_pon_is_warm_reset();
@@ -4163,17 +4194,12 @@
 	wake_lock_destroy(&chip->cv_wake_lock);
 error_resource:
 error_read:
-	kfree(chip);
 	return rc;
 }
 
-static int __devexit
-qpnp_bms_remove(struct spmi_device *spmi)
+static int qpnp_bms_remove(struct spmi_device *spmi)
 {
-	struct qpnp_bms_chip *chip = dev_get_drvdata(&spmi->dev);
-
 	dev_set_drvdata(&spmi->dev, NULL);
-	kfree(chip);
 	return 0;
 }
 
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f9e05fc..64ad940 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -31,6 +31,7 @@
 #include <linux/of_batterydata.h>
 #include <linux/qpnp-revid.h>
 #include <linux/android_alarm.h>
+#include <linux/spinlock.h>
 
 /* Interrupt offsets */
 #define INT_RT_STS(base)			(base + 0x10)
@@ -81,11 +82,13 @@
 #define CHGR_USB_USB_SUSP			0x47
 #define CHGR_USB_USB_OTG_CTL			0x48
 #define CHGR_USB_ENUM_T_STOP			0x4E
+#define CHGR_USB_TRIM				0xF1
 #define CHGR_CHG_TEMP_THRESH			0x66
 #define CHGR_BAT_IF_PRES_STATUS			0x08
 #define CHGR_STATUS				0x09
 #define CHGR_BAT_IF_VCP				0x42
 #define CHGR_BAT_IF_BATFET_CTRL1		0x90
+#define CHGR_BAT_IF_BATFET_CTRL4		0x93
 #define CHGR_BAT_IF_SPARE			0xDF
 #define CHGR_MISC_BOOT_DONE			0x42
 #define CHGR_BUCK_PSTG_CTRL			0x73
@@ -241,6 +244,7 @@
  * @btc_disabled		Flag to disable btc (disables hot and cold irqs)
  * @max_voltage_mv:		the max volts the batt should be charged up to
  * @min_voltage_mv:		min battery voltage before turning the FET on
+ * @batt_weak_voltage_mv:	Weak battery voltage threshold
  * @max_bat_chg_current:	maximum battery charge current in mA
  * @warm_bat_chg_ma:	warm battery maximum charge current in mA
  * @cool_bat_chg_ma:	cool battery maximum charge current in mA
@@ -290,14 +294,19 @@
 	struct qpnp_chg_irq		chg_vbatdet_lo;
 	struct qpnp_chg_irq		batt_pres;
 	struct qpnp_chg_irq		batt_temp_ok;
+	struct qpnp_chg_irq		coarse_det_usb;
 	bool				bat_is_cool;
 	bool				bat_is_warm;
 	bool				chg_done;
 	bool				charger_monitor_checked;
 	bool				usb_present;
+	u8				usbin_health;
+	bool				usb_coarse_det;
 	bool				dc_present;
 	bool				batt_present;
 	bool				charging_disabled;
+	bool				ovp_monitor_enable;
+	bool				usb_valid_check_ovp;
 	bool				btc_disabled;
 	bool				use_default_batt_values;
 	bool				duty_cycle_100p;
@@ -308,6 +317,7 @@
 	unsigned int			safe_voltage_mv;
 	unsigned int			max_voltage_mv;
 	unsigned int			min_voltage_mv;
+	unsigned int			batt_weak_voltage_mv;
 	int				prev_usb_max_ma;
 	int				set_vddmax_mv;
 	int				delta_vddmax_mv;
@@ -341,14 +351,19 @@
 	struct work_struct		adc_disable_work;
 	struct delayed_work		arb_stop_work;
 	struct delayed_work		eoc_work;
+	struct delayed_work		usbin_health_check;
 	struct work_struct		soc_check_work;
 	struct delayed_work		aicl_check_work;
 	struct qpnp_chg_regulator	otg_vreg;
 	struct qpnp_chg_regulator	boost_vreg;
 	struct qpnp_chg_regulator	batfet_vreg;
+	bool				batfet_ext_en;
+	struct work_struct		batfet_lcl_work;
 	struct qpnp_vadc_chip		*vadc_dev;
 	struct qpnp_adc_tm_chip		*adc_tm_dev;
 	struct mutex			jeita_configure_lock;
+	spinlock_t			usbin_health_monitor_lock;
+	struct mutex			batfet_vreg_lock;
 	struct alarm			reduce_power_stage_alarm;
 	struct work_struct		reduce_power_stage_work;
 	bool				power_stage_workaround_running;
@@ -386,7 +401,13 @@
 	[COLD_THD_80_PCT] = BIT(1),
 };
 
-	static inline int
+enum usbin_health {
+	USBIN_UNKNOW,
+	USBIN_OK,
+	USBIN_OVP,
+};
+
+static inline int
 get_bpd(const char *name)
 {
 	int i = 0;
@@ -599,6 +620,58 @@
 	return (usbin_valid_rt_sts & USB_VALID_BIT) ? 1 : 0;
 }
 
+#define USB_VALID_MASK 0xC0
+#define USB_COARSE_DET 0x10
+#define USB_VALID_UVP_VALUE    0x00
+#define USB_VALID_OVP_VALUE    0x40
+static int
+qpnp_chg_check_usb_coarse_det(struct qpnp_chg_chip *chip)
+{
+	u8 usbin_chg_rt_sts;
+	int rc;
+	rc = qpnp_chg_read(chip, &usbin_chg_rt_sts,
+		chip->usb_chgpth_base + CHGR_STATUS , 1);
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+			chip->usb_chgpth_base + CHGR_STATUS, rc);
+		return rc;
+	}
+	return (usbin_chg_rt_sts & USB_COARSE_DET) ? 1 : 0;
+}
+
+static int
+qpnp_chg_check_usbin_health(struct qpnp_chg_chip *chip)
+{
+	u8 usbin_chg_rt_sts, usbin_health = 0;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &usbin_chg_rt_sts,
+		chip->usb_chgpth_base + CHGR_STATUS , 1);
+
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+		chip->usb_chgpth_base + CHGR_STATUS, rc);
+		return rc;
+	}
+
+	pr_debug("chgr usb sts 0x%x\n", usbin_chg_rt_sts);
+	if ((usbin_chg_rt_sts & USB_COARSE_DET) == USB_COARSE_DET) {
+		if ((usbin_chg_rt_sts & USB_VALID_MASK)
+			 == USB_VALID_OVP_VALUE) {
+			usbin_health = USBIN_OVP;
+			pr_err("Over voltage charger inserted\n");
+		} else if ((usbin_chg_rt_sts & USB_VALID_BIT) != 0) {
+			usbin_health = USBIN_OK;
+			pr_debug("Valid charger inserted\n");
+		}
+	} else {
+		usbin_health = USBIN_UNKNOW;
+		pr_debug("Charger plug out\n");
+	}
+
+	return usbin_health;
+}
+
 static int
 qpnp_chg_is_dc_chg_plugged_in(struct qpnp_chg_chip *chip)
 {
@@ -676,6 +749,48 @@
 }
 
 static int
+qpnp_chg_iusb_trim_get(struct qpnp_chg_chip *chip)
+{
+	int rc = 0;
+	u8 trim_reg;
+
+	rc = qpnp_chg_read(chip, &trim_reg,
+			chip->usb_chgpth_base + CHGR_USB_TRIM, 1);
+	if (rc) {
+		pr_err("failed to read USB_TRIM rc=%d\n", rc);
+		return 0;
+	}
+
+	return trim_reg;
+}
+
+static int
+qpnp_chg_iusb_trim_set(struct qpnp_chg_chip *chip, int trim)
+{
+	int rc = 0;
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->usb_chgpth_base + SEC_ACCESS,
+		0xFF,
+		0xA5, 1);
+	if (rc) {
+		pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->usb_chgpth_base + CHGR_USB_TRIM,
+		0xFF,
+		trim, 1);
+	if (rc) {
+		pr_err("failed to write USB TRIM rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int
 qpnp_chg_iusbmax_set(struct qpnp_chg_chip *chip, int mA)
 {
 	int rc = 0;
@@ -737,7 +852,7 @@
 #define QPNP_CHG_VINMIN_MAX_MV		9600
 #define QPNP_CHG_VINMIN_STEP_MV		50
 #define QPNP_CHG_VINMIN_STEP_HIGH_MV	200
-#define QPNP_CHG_VINMIN_MASK		0x1F
+#define QPNP_CHG_VINMIN_MASK		0x3F
 #define QPNP_CHG_VINMIN_MIN_VAL	0x10
 static int
 qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
@@ -792,6 +907,26 @@
 	return vin_min_mv;
 }
 
+#define QPNP_CHG_VBATWEAK_MIN_MV	2100
+#define QPNP_CHG_VBATWEAK_MAX_MV	3600
+#define QPNP_CHG_VBATWEAK_STEP_MV	100
+static int
+qpnp_chg_vbatweak_set(struct qpnp_chg_chip *chip, int vbatweak_mv)
+{
+	u8 temp;
+
+	if (vbatweak_mv < QPNP_CHG_VBATWEAK_MIN_MV
+			|| vbatweak_mv > QPNP_CHG_VBATWEAK_MAX_MV)
+		return -EINVAL;
+
+	temp = (vbatweak_mv - QPNP_CHG_VBATWEAK_MIN_MV)
+			/ QPNP_CHG_VBATWEAK_STEP_MV;
+
+	pr_debug("voltage=%d setting %02x\n", vbatweak_mv, temp);
+	return qpnp_chg_write(chip, &temp,
+		chip->chgr_base + CHGR_VBAT_WEAK, 1);
+}
+
 static int
 qpnp_chg_usb_iusbmax_get(struct qpnp_chg_chip *chip)
 {
@@ -1117,12 +1252,128 @@
 				chip->delta_vddmax_mv);
 }
 
+static void
+qpnp_usbin_health_check_work(struct work_struct *work)
+{
+	int usbin_health = 0;
+	u8 psy_health_sts = 0;
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct qpnp_chg_chip *chip = container_of(dwork,
+				struct qpnp_chg_chip, usbin_health_check);
+
+	usbin_health = qpnp_chg_check_usbin_health(chip);
+	spin_lock(&chip->usbin_health_monitor_lock);
+	if (chip->usbin_health != usbin_health) {
+		pr_debug("health_check_work: pr_usbin_health = %d, usbin_health = %d",
+			chip->usbin_health, usbin_health);
+		chip->usbin_health = usbin_health;
+		if (usbin_health == USBIN_OVP)
+			psy_health_sts = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+		else if (usbin_health == USBIN_OK)
+			psy_health_sts = POWER_SUPPLY_HEALTH_GOOD;
+		power_supply_set_health_state(chip->usb_psy, psy_health_sts);
+		power_supply_changed(chip->usb_psy);
+	}
+	/* enable OVP monitor in usb valid after coarse-det complete */
+	chip->usb_valid_check_ovp = true;
+	spin_unlock(&chip->usbin_health_monitor_lock);
+	return;
+}
+
+#define USB_VALID_DEBOUNCE_TIME_MASK		0x3
+#define USB_DEB_BYPASS		0x0
+#define USB_DEB_5MS			0x1
+#define USB_DEB_10MS		0x2
+#define USB_DEB_20MS		0x3
+static irqreturn_t
+qpnp_chg_coarse_det_usb_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+	int host_mode, rc = 0;
+	int debounce[] = {
+		[USB_DEB_BYPASS] = 0,
+		[USB_DEB_5MS] = 5,
+		[USB_DEB_10MS] = 10,
+		[USB_DEB_20MS] = 20 };
+	u8 ovp_ctl;
+	bool usb_coarse_det;
+
+	host_mode = qpnp_chg_is_otg_en_set(chip);
+	usb_coarse_det = qpnp_chg_check_usb_coarse_det(chip);
+	pr_debug("usb coarse-det triggered: %d host_mode: %d\n",
+			usb_coarse_det, host_mode);
+
+	if (host_mode)
+		return IRQ_HANDLED;
+	/* ignore to monitor OVP in usbin valid irq handler
+	 if the coarse-det fired first, do the OVP state monitor
+	 in the usbin_health_check work, and after the work,
+	 enable monitor OVP in usbin valid irq handler */
+	chip->usb_valid_check_ovp = false;
+	if (chip->usb_coarse_det ^ usb_coarse_det) {
+		chip->usb_coarse_det = usb_coarse_det;
+		if (usb_coarse_det) {
+			/* usb coarse-det rising edge, check the usbin_valid
+			debounce time setting, and start a delay work to
+			check the OVP status*/
+			rc = qpnp_chg_read(chip, &ovp_ctl,
+					chip->usb_chgpth_base + USB_OVP_CTL, 1);
+
+			if (rc) {
+				pr_err("spmi read failed: addr=%03X, rc=%d\n",
+					chip->usb_chgpth_base + USB_OVP_CTL,
+					rc);
+				return rc;
+			}
+			ovp_ctl = ovp_ctl & USB_VALID_DEBOUNCE_TIME_MASK;
+			schedule_delayed_work(&chip->usbin_health_check,
+					msecs_to_jiffies(debounce[ovp_ctl]));
+		} else {
+			/* usb coarse-det rising edge, set the usb psy health
+			status to unknown */
+			pr_debug("usb coarse det clear, set usb health to unknown\n");
+			chip->usbin_health = USBIN_UNKNOW;
+			power_supply_set_health_state(chip->usb_psy,
+				POWER_SUPPLY_HEALTH_UNKNOWN);
+			power_supply_changed(chip->usb_psy);
+		}
+
+	}
+	return IRQ_HANDLED;
+}
+
+#define BATFET_LPM_MASK		0xC0
+#define BATFET_LPM		0x40
+#define BATFET_NO_LPM		0x00
+static int
+qpnp_chg_regulator_batfet_set(struct qpnp_chg_chip *chip, bool enable)
+{
+	int rc = 0;
+
+	if (chip->charging_disabled || !chip->bat_if_base)
+		return rc;
+
+	if (chip->type == SMBB)
+		rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + CHGR_BAT_IF_SPARE,
+			BATFET_LPM_MASK,
+			enable ? BATFET_NO_LPM : BATFET_LPM, 1);
+	else
+		rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + CHGR_BAT_IF_BATFET_CTRL4,
+			BATFET_LPM_MASK,
+			enable ? BATFET_NO_LPM : BATFET_LPM, 1);
+
+	return rc;
+}
+
 #define ENUM_T_STOP_BIT		BIT(0)
 static irqreturn_t
 qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
-	int usb_present, host_mode;
+	int usb_present, host_mode, usbin_health;
+	u8 psy_health_sts;
 
 	usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
 	host_mode = qpnp_chg_is_otg_en_set(chip);
@@ -1136,15 +1387,55 @@
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
 		if (!usb_present) {
+			/* when a valid charger inserted, and increase the
+			 *  charger voltage to OVP threshold, then
+			 *  usb_in_valid falling edge interrupt triggers.
+			 *  So we handle the OVP monitor here, and ignore
+			 *  other health state changes */
+			if (chip->ovp_monitor_enable &&
+				       (chip->usb_valid_check_ovp)) {
+				usbin_health =
+					qpnp_chg_check_usbin_health(chip);
+				if (chip->usbin_health != usbin_health) {
+					chip->usbin_health = usbin_health;
+					if (usbin_health == USBIN_OVP)
+						psy_health_sts =
+					POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+					power_supply_set_health_state(
+						chip->usb_psy,
+						psy_health_sts);
+					power_supply_changed(chip->usb_psy);
+				}
+			}
 			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
 				chip->delta_vddmax_mv = 0;
 				qpnp_chg_set_appropriate_vddmax(chip);
+				chip->chg_done = false;
 			}
 			qpnp_chg_usb_suspend_enable(chip, 1);
-			if (!qpnp_chg_is_dc_chg_plugged_in(chip))
-				chip->chg_done = false;
 			chip->prev_usb_max_ma = -EINVAL;
 		} else {
+			/* when OVP clamped usbin, and then decrease
+			 * the charger voltage to lower than the OVP
+			 * threshold, a usbin_valid rising edge
+			 * interrupt triggered. So we change the usb
+			 * psy health state back to good */
+			if (chip->ovp_monitor_enable &&
+				       (chip->usb_valid_check_ovp)) {
+				usbin_health =
+					qpnp_chg_check_usbin_health(chip);
+				if (chip->usbin_health != usbin_health) {
+					chip->usbin_health = usbin_health;
+					 if (usbin_health == USBIN_OK)
+						psy_health_sts =
+						POWER_SUPPLY_HEALTH_GOOD;
+					power_supply_set_health_state(
+						chip->usb_psy,
+						psy_health_sts);
+					power_supply_changed(chip->usb_psy);
+				}
+			}
+
 			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
 				chip->delta_vddmax_mv = 0;
 				qpnp_chg_set_appropriate_vddmax(chip);
@@ -1155,6 +1446,7 @@
 		}
 
 		power_supply_set_present(chip->usb_psy, chip->usb_present);
+		schedule_work(&chip->batfet_lcl_work);
 	}
 
 	return IRQ_HANDLED;
@@ -1232,6 +1524,7 @@
 		power_supply_changed(&chip->dc_psy);
 		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+		schedule_work(&chip->batfet_lcl_work);
 	}
 
 	return IRQ_HANDLED;
@@ -1346,6 +1639,7 @@
 	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 	case POWER_SUPPLY_PROP_COOL_TEMP:
 	case POWER_SUPPLY_PROP_WARM_TEMP:
@@ -1456,6 +1750,7 @@
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
 	POWER_SUPPLY_PROP_VOLTAGE_MIN,
 	POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
@@ -1478,7 +1773,11 @@
 static int charger_monitor;
 module_param(charger_monitor, int, 0644);
 
+static int ext_ovp_present;
+module_param(ext_ovp_present, int, 0444);
+
 #define USB_WALL_THRESHOLD_MA	500
+#define OVP_USB_WALL_THRESHOLD_MA	200
 static int
 qpnp_power_get_property_mains(struct power_supply *psy,
 				  enum power_supply_property psp,
@@ -1693,7 +1992,7 @@
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};
-	int battery_status, charger_in;
+	int battery_status, bms_status, soc, charger_in;
 
 	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
 		return DEFAULT_CAPACITY;
@@ -1701,28 +2000,32 @@
 	if (chip->bms_psy) {
 		chip->bms_psy->get_property(chip->bms_psy,
 				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		soc = ret.intval;
 		battery_status = get_prop_batt_status(chip);
+		chip->bms_psy->get_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_STATUS, &ret);
+		bms_status = ret.intval;
 		charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
 			qpnp_chg_is_dc_chg_plugged_in(chip);
 
 		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+				&& bms_status != POWER_SUPPLY_STATUS_CHARGING
 				&& charger_in
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
-				&& ret.intval <= chip->soc_resume_limit) {
-			pr_debug("resuming charging at %d%% soc\n",
-					ret.intval);
+				&& soc <= chip->soc_resume_limit) {
+			pr_debug("resuming charging at %d%% soc\n", soc);
 			chip->resuming_charging = true;
 			qpnp_chg_set_appropriate_vbatdet(chip);
 			qpnp_chg_charge_en(chip, !chip->charging_disabled);
 		}
-		if (ret.intval == 0) {
+		if (soc == 0) {
 			if (!qpnp_chg_is_usb_chg_plugged_in(chip)
 				&& !qpnp_chg_is_usb_chg_plugged_in(chip))
 				pr_warn_ratelimited("Battery 0, CHG absent\n");
 		}
-		return ret.intval;
+		return soc;
 	} else {
 		pr_debug("No BMS supply registered return 50\n");
 	}
@@ -1816,8 +2119,12 @@
 			if (((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
 					&& (charger_monitor ||
 					!chip->charger_monitor_checked)) {
-				qpnp_chg_iusbmax_set(chip,
+				if (!ext_ovp_present)
+					qpnp_chg_iusbmax_set(chip,
 						USB_WALL_THRESHOLD_MA);
+				else
+					qpnp_chg_iusbmax_set(chip,
+						OVP_USB_WALL_THRESHOLD_MA);
 			} else {
 				qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			}
@@ -1909,6 +2216,9 @@
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
 		val->intval = qpnp_chg_usb_iusbmax_get(chip) * 1000;
 		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
+		val->intval = qpnp_chg_iusb_trim_get(chip);
+		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 		val->intval = qpnp_chg_vinmin_get(chip) * 1000;
 		break;
@@ -2349,20 +2659,50 @@
 	.list_voltage		= qpnp_chg_regulator_boost_list_voltage,
 };
 
-#define BATFET_LPM_MASK		0xC0
-#define BATFET_LPM		0x40
-#define BATFET_NO_LPM		0x00
+static int
+qpnp_chg_bat_if_batfet_reg_enabled(struct qpnp_chg_chip *chip)
+{
+	int rc = 0;
+	u8 reg = 0;
+
+	if (!chip->bat_if_base)
+		return rc;
+
+	if (chip->type == SMBB)
+		rc = qpnp_chg_read(chip, &reg,
+				chip->bat_if_base + CHGR_BAT_IF_SPARE, 1);
+	else
+		rc = qpnp_chg_read(chip, &reg,
+			chip->bat_if_base + CHGR_BAT_IF_BATFET_CTRL4, 1);
+
+	if (rc) {
+		pr_err("failed to read batt_if rc=%d\n", rc);
+		return rc;
+	}
+
+	if ((reg & BATFET_LPM_MASK) == BATFET_NO_LPM)
+		return 1;
+
+	return 0;
+}
+
 static int
 qpnp_chg_regulator_batfet_enable(struct regulator_dev *rdev)
 {
 	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
-	int rc;
+	int rc = 0;
 
-	rc = qpnp_chg_masked_write(chip,
-			chip->bat_if_base + CHGR_BAT_IF_SPARE,
-			BATFET_LPM_MASK, BATFET_NO_LPM, 1);
-	if (rc)
-		pr_err("failed to write to batt_if rc=%d\n", rc);
+	mutex_lock(&chip->batfet_vreg_lock);
+	/* Only enable if not already enabled */
+	if (!qpnp_chg_bat_if_batfet_reg_enabled(chip)) {
+		rc = qpnp_chg_regulator_batfet_set(chip, 1);
+		if (rc)
+			pr_err("failed to write to batt_if rc=%d\n", rc);
+	}
+
+	chip->batfet_ext_en = true;
+	mutex_unlock(&chip->batfet_vreg_lock);
+
 	return rc;
 }
 
@@ -2370,13 +2710,20 @@
 qpnp_chg_regulator_batfet_disable(struct regulator_dev *rdev)
 {
 	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
-	int rc;
+	int rc = 0;
 
-	rc = qpnp_chg_masked_write(chip,
-			chip->bat_if_base + CHGR_BAT_IF_SPARE,
-			BATFET_LPM_MASK, BATFET_LPM, 1);
-	if (rc)
-		pr_err("failed to write to batt_if rc=%d\n", rc);
+	mutex_lock(&chip->batfet_vreg_lock);
+	/* Don't allow disable if charger connected */
+	if (!qpnp_chg_is_usb_chg_plugged_in(chip) &&
+			!qpnp_chg_is_dc_chg_plugged_in(chip)) {
+		rc = qpnp_chg_regulator_batfet_set(chip, 0);
+		if (rc)
+			pr_err("failed to write to batt_if rc=%d\n", rc);
+	}
+
+	chip->batfet_ext_en = false;
+	mutex_unlock(&chip->batfet_vreg_lock);
+
 	return rc;
 }
 
@@ -2384,20 +2731,8 @@
 qpnp_chg_regulator_batfet_is_enabled(struct regulator_dev *rdev)
 {
 	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
-	int rc;
-	u8 reg;
 
-	rc = qpnp_chg_read(chip, &reg,
-				chip->bat_if_base + CHGR_BAT_IF_SPARE, 1);
-	if (rc) {
-		pr_err("failed to read batt_if rc=%d\n", rc);
-		return rc;
-	}
-
-	if (reg && BATFET_LPM_MASK == BATFET_NO_LPM)
-		return 1;
-
-	return 0;
+	return chip->batfet_ext_en;
 }
 
 static struct regulator_ops qpnp_chg_batfet_vreg_ops = {
@@ -2886,6 +3221,25 @@
 }
 
 static void
+qpnp_chg_batfet_lcl_work(struct work_struct *work)
+{
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, batfet_lcl_work);
+
+	mutex_lock(&chip->batfet_vreg_lock);
+	if (qpnp_chg_is_usb_chg_plugged_in(chip) ||
+			qpnp_chg_is_dc_chg_plugged_in(chip)) {
+		qpnp_chg_regulator_batfet_set(chip, 1);
+		pr_debug("disabled ULPM\n");
+	} else if (!chip->batfet_ext_en && !qpnp_chg_is_usb_chg_plugged_in(chip)
+			&& !qpnp_chg_is_dc_chg_plugged_in(chip)) {
+		qpnp_chg_regulator_batfet_set(chip, 0);
+		pr_debug("enabled ULPM\n");
+	}
+	mutex_unlock(&chip->batfet_vreg_lock);
+}
+
+static void
 qpnp_chg_reduce_power_stage_work(struct work_struct *work)
 {
 	struct qpnp_chg_chip *chip = container_of(work,
@@ -2970,6 +3324,9 @@
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
 		qpnp_chg_iusbmax_set(chip, val->intval / 1000);
 		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
+		qpnp_chg_iusb_trim_set(chip, val->intval);
+		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 		qpnp_chg_vinmin_set(chip, val->intval / 1000);
 		break;
@@ -3174,6 +3531,27 @@
 		case SMBB_USB_CHGPTH_SUBTYPE:
 		case SMBBP_USB_CHGPTH_SUBTYPE:
 		case SMBCL_USB_CHGPTH_SUBTYPE:
+			if (chip->ovp_monitor_enable) {
+				chip->coarse_det_usb.irq =
+					spmi_get_irq_byname(spmi,
+					spmi_resource, "coarse-det-usb");
+				if (chip->coarse_det_usb.irq < 0) {
+					pr_err("Can't get coarse-det irq\n");
+					return rc;
+				}
+				rc = devm_request_irq(chip->dev,
+					chip->coarse_det_usb.irq,
+					qpnp_chg_coarse_det_usb_irq_handler,
+					IRQF_TRIGGER_RISING |
+					IRQF_TRIGGER_FALLING,
+					"coarse-det-usb", chip);
+				if (rc < 0) {
+					pr_err("Can't req %d coarse-det: %d\n",
+						chip->coarse_det_usb.irq, rc);
+					return rc;
+				}
+			}
+
 			chip->usbin_valid.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "usbin-valid");
 			if (chip->usbin_valid.irq < 0) {
@@ -3309,6 +3687,8 @@
 	case SMBB_CHGR_SUBTYPE:
 	case SMBBP_CHGR_SUBTYPE:
 	case SMBCL_CHGR_SUBTYPE:
+		qpnp_chg_vbatweak_set(chip, chip->batt_weak_voltage_mv);
+
 		rc = qpnp_chg_vinmin_set(chip, chip->min_voltage_mv);
 		if (rc) {
 			pr_debug("failed setting  min_voltage rc=%d\n", rc);
@@ -3631,6 +4011,7 @@
 	OF_PROP_READ(chip, hot_batt_p, "batt-hot-percentage", rc, 1);
 	OF_PROP_READ(chip, cold_batt_p, "batt-cold-percentage", rc, 1);
 	OF_PROP_READ(chip, soc_resume_limit, "resume-soc", rc, 1);
+	OF_PROP_READ(chip, batt_weak_voltage_mv, "vbatweak-mv", rc, 1);
 
 	if (rc)
 		return rc;
@@ -3671,10 +4052,16 @@
 	chip->btc_disabled = of_property_read_bool(chip->spmi->dev.of_node,
 					"qcom,btc-disabled");
 
+	ext_ovp_present = of_property_read_bool(chip->spmi->dev.of_node,
+					"qcom,ext-ovp-present");
+
 	/* Get the charging-disabled property */
 	chip->charging_disabled = of_property_read_bool(chip->spmi->dev.of_node,
 					"qcom,charging-disabled");
 
+	chip->ovp_monitor_enable = of_property_read_bool(chip->spmi->dev.of_node,
+					"qcom,ovp-monitor-en");
+
 	/* Get the duty-cycle-100p property */
 	chip->duty_cycle_100p = of_property_read_bool(
 					chip->spmi->dev.of_node,
@@ -3742,10 +4129,14 @@
 	}
 
 	mutex_init(&chip->jeita_configure_lock);
+	spin_lock_init(&chip->usbin_health_monitor_lock);
 	alarm_init(&chip->reduce_power_stage_alarm, ANDROID_ALARM_RTC_WAKEUP,
 			qpnp_chg_reduce_power_stage_callback);
 	INIT_WORK(&chip->reduce_power_stage_work,
 			qpnp_chg_reduce_power_stage_work);
+	mutex_init(&chip->batfet_vreg_lock);
+	INIT_WORK(&chip->batfet_lcl_work,
+			qpnp_chg_batfet_lcl_work);
 
 	/* Get all device tree properties */
 	rc = qpnp_charger_read_dt_props(chip);
@@ -3955,6 +4346,8 @@
 
 	INIT_DELAYED_WORK(&chip->eoc_work, qpnp_eoc_work);
 	INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+	INIT_DELAYED_WORK(&chip->usbin_health_check,
+			qpnp_usbin_health_check_work);
 	INIT_WORK(&chip->soc_check_work, qpnp_chg_soc_check_work);
 	INIT_DELAYED_WORK(&chip->aicl_check_work, qpnp_aicl_check_work);
 
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index 1d60e97..4682e9c 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -98,7 +98,7 @@
 				wake_unlock(&alarm_wake_lock);
 		}
 		alarm_enabled &= ~alarm_type_mask;
-		if (alarm_type == ANDROID_ALARM_RTC_WAKEUP)
+		if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
 			set_power_on_alarm(0);
 		spin_unlock_irqrestore(&alarm_slock, flags);
 		break;
@@ -127,7 +127,7 @@
 		alarm_start_range(&alarms[alarm_type],
 			timespec_to_ktime(new_alarm_time),
 			timespec_to_ktime(new_alarm_time));
-		if ((alarm_type == ANDROID_ALARM_RTC_WAKEUP) &&
+		if ((alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP) &&
 				(ANDROID_ALARM_BASE_CMD(cmd) ==
 				 ANDROID_ALARM_SET(0)))
 			set_power_on_alarm(new_alarm_time.tv_sec);
@@ -171,6 +171,7 @@
 		switch (alarm_type) {
 		case ANDROID_ALARM_RTC_WAKEUP:
 		case ANDROID_ALARM_RTC:
+		case ANDROID_ALARM_RTC_POWEROFF_WAKEUP:
 			getnstimeofday(&tmp_time);
 			break;
 		case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 1648cba..7d59e28 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -81,7 +81,8 @@
 {
 	struct alarm *alarm;
 	bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
-			base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
+			base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP] ||
+			base == &alarms[ANDROID_ALARM_RTC_POWEROFF_WAKEUP];
 
 	if (base->stopped) {
 		pr_alarm(FLOW, "changed alarm while setting the wall time\n");
@@ -423,15 +424,25 @@
 	hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
 	hrtimer_cancel(&alarms[
 			ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
+	hrtimer_cancel(&alarms[
+			ANDROID_ALARM_RTC_POWEROFF_WAKEUP].timer);
 
 	tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
 	if (tmp_queue->first)
 		wakeup_queue = tmp_queue;
+
 	tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
 	if (tmp_queue->first && (!wakeup_queue ||
 				hrtimer_get_expires(&tmp_queue->timer).tv64 <
 				hrtimer_get_expires(&wakeup_queue->timer).tv64))
 		wakeup_queue = tmp_queue;
+
+	tmp_queue = &alarms[ANDROID_ALARM_RTC_POWEROFF_WAKEUP];
+	if (tmp_queue->first && (!wakeup_queue ||
+				hrtimer_get_expires(&tmp_queue->timer).tv64 <
+				hrtimer_get_expires(&wakeup_queue->timer).tv64))
+		wakeup_queue = tmp_queue;
+
 	if (wakeup_queue) {
 		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
 		getnstimeofday(&wall_time);
@@ -466,6 +477,8 @@
 									false);
 			update_timer_locked(&alarms[
 				ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
+			update_timer_locked(&alarms[
+					ANDROID_ALARM_RTC_POWEROFF_WAKEUP], false);
 			err = -EBUSY;
 			spin_unlock_irqrestore(&alarm_slock, flags);
 		}
@@ -489,6 +502,8 @@
 	update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
 	update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
 									false);
+	update_timer_locked(&alarms[ANDROID_ALARM_RTC_POWEROFF_WAKEUP],
+									false);
 	spin_unlock_irqrestore(&alarm_slock, flags);
 
 	return 0;
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 3abc3b9..b7bf74e 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 
 #include "binder.h"
 
@@ -1488,6 +1489,10 @@
 			return_error = BR_DEAD_REPLY;
 			goto err_dead_binder;
 		}
+		if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
+			return_error = BR_FAILED_REPLY;
+			goto err_invalid_target_handle;
+		}
 		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
 			struct binder_transaction *tmp;
 			tmp = thread->transaction_stack;
@@ -1633,6 +1638,10 @@
 					fp->cookie, node->cookie);
 				goto err_binder_get_ref_for_node_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_for_node_failed;
+			}
 			ref = binder_get_ref_for_node(target_proc, node);
 			if (ref == NULL) {
 				return_error = BR_FAILED_REPLY;
@@ -1662,6 +1671,10 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_binder_get_ref_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_failed;
+			}
 			if (ref->node->proc == target_proc) {
 				if (fp->type == BINDER_TYPE_HANDLE)
 					fp->type = BINDER_TYPE_BINDER;
@@ -1715,6 +1728,11 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_fget_failed;
 			}
+			if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
+				fput(file);
+				return_error = BR_FAILED_REPLY;
+				goto err_get_unused_fd_failed;
+			}
 			target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
 			if (target_fd < 0) {
 				fput(file);
@@ -2748,6 +2766,9 @@
 			ret = -EBUSY;
 			goto err;
 		}
+		ret = security_binder_set_context_mgr(proc->tsk);
+		if (ret < 0)
+			goto err;
 		if (binder_context_mgr_uid != -1) {
 			if (binder_context_mgr_uid != current->cred->euid) {
 				binder_debug(BINDER_DEBUG_TOP_ERRORS,
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 7dcd45f..cf1801b 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -169,6 +169,19 @@
 #define QPNP_MIN_TIME			2000
 #define QPNP_MAX_TIME			2100
 
+struct qpnp_adc_thr_client_info {
+	struct list_head		list;
+	struct qpnp_adc_tm_btm_param	*btm_param;
+	int32_t				low_thr_requested;
+	int32_t				high_thr_requested;
+	enum qpnp_state_request		state_requested;
+	enum qpnp_state_request		state_req_copy;
+	bool				low_thr_set;
+	bool				high_thr_set;
+	bool				notify_low_thr;
+	bool				notify_high_thr;
+};
+
 struct qpnp_adc_tm_sensor {
 	struct thermal_zone_device	*tz_dev;
 	struct qpnp_adc_tm_chip		*chip;
@@ -181,14 +194,13 @@
 	uint32_t			btm_channel_num;
 	uint32_t			vadc_channel_num;
 	struct work_struct		work;
-	struct qpnp_adc_tm_btm_param	*btm_param;
 	bool				thermal_node;
-	bool				low_thr_notify;
-	bool				high_thr_notify;
 	uint32_t			scale_type;
+	struct list_head		thr_list;
 };
 
 struct qpnp_adc_tm_chip {
+	struct device			*dev;
 	struct qpnp_adc_drv		*adc;
 	struct list_head		list;
 	bool				adc_tm_initialized;
@@ -202,53 +214,62 @@
 LIST_HEAD(qpnp_adc_tm_device_list);
 
 struct qpnp_adc_tm_trip_reg_type {
-	uint16_t low_thr_lsb_addr;
-	uint16_t low_thr_msb_addr;
-	uint16_t high_thr_lsb_addr;
-	uint16_t high_thr_msb_addr;
-	u8 multi_meas_en;
-	u8 low_thr_int_chan_en;
-	u8 high_thr_int_chan_en;
-	u8 meas_interval_ctl;
+	enum qpnp_adc_tm_channel_select	btm_amux_chan;
+	uint16_t			low_thr_lsb_addr;
+	uint16_t			low_thr_msb_addr;
+	uint16_t			high_thr_lsb_addr;
+	uint16_t			high_thr_msb_addr;
+	u8				multi_meas_en;
+	u8				low_thr_int_chan_en;
+	u8				high_thr_int_chan_en;
+	u8				meas_interval_ctl;
 };
 
 static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
-	[QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
+		QPNP_M0_LOW_THR_LSB,
 		QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
 		QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
 		QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
+		QPNP_M1_LOW_THR_LSB,
 		QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
 		QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
 		QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
+		QPNP_M2_LOW_THR_LSB,
 		QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
 		QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
 		QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
+		QPNP_M3_LOW_THR_LSB,
 		QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
 		QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
 		QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
+		QPNP_M4_LOW_THR_LSB,
 		QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
 		QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
 		QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
+		QPNP_M5_LOW_THR_LSB,
 		QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
 		QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
 		QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
+		QPNP_M6_LOW_THR_LSB,
 		QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
 		QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
 		QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
+		QPNP_M7_LOW_THR_LSB,
 		QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
 		QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
@@ -384,6 +405,25 @@
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
+						uint32_t *btm_chan_idx)
+{
+	int rc = 0, i;
+	bool chan_found = false;
+
+	for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+		if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+			*btm_chan_idx = i;
+			chan_found = true;
+		}
+	}
+
+	if (!chan_found)
+		return -EINVAL;
+
+	return rc;
+}
+
 static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
 							uint32_t btm_chan_num)
 {
@@ -433,6 +473,7 @@
 {
 	int rc;
 	u8 meas_interval_timer2 = 0;
+	uint32_t btm_chan_idx = 0;
 
 	/* Configure kernel clients to timer1 */
 	switch (chan_prop->timer_select) {
@@ -489,11 +530,60 @@
 	}
 
 	/* Select the timer to use for the corresponding channel */
-	adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+	adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
 
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_add_to_list(struct qpnp_adc_tm_chip *chip,
+				uint32_t dt_index,
+				struct qpnp_adc_tm_btm_param *param,
+				struct qpnp_vadc_chan_properties *chan_prop)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	bool client_info_exists = false;
+
+	list_for_each_entry(client_info,
+			&chip->sensor[dt_index].thr_list, list) {
+		if (client_info->btm_param == param) {
+			client_info->low_thr_requested = chan_prop->low_thr;
+			client_info->high_thr_requested = chan_prop->high_thr;
+			client_info->state_requested = param->state_request;
+			client_info->state_req_copy = param->state_request;
+			client_info->notify_low_thr = false;
+			client_info->notify_high_thr = false;
+			client_info_exists = true;
+			pr_debug("client found\n");
+		}
+	}
+
+	if (!client_info_exists) {
+		client_info = devm_kzalloc(chip->dev,
+			sizeof(struct qpnp_adc_thr_client_info), GFP_KERNEL);
+		if (!client_info) {
+			pr_err("%s: kzalloc() failed.\n", __func__);
+			return -ENOMEM;
+		}
+
+		pr_debug("new client\n");
+		client_info->btm_param = param;
+		client_info->low_thr_requested = chan_prop->low_thr;
+		client_info->high_thr_requested = chan_prop->high_thr;
+		client_info->state_requested = param->state_request;
+		client_info->state_req_copy = param->state_request;
+
+		list_add_tail(&client_info->list,
+					&chip->sensor[dt_index].thr_list);
+	}
+
+	return 0;
+}
+
 static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
 		uint16_t addr, u8 mask, bool state)
 {
@@ -522,55 +612,137 @@
 }
 
 static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
-			uint32_t btm_chan,
-			struct qpnp_vadc_chan_properties *chan_prop)
+			uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
 {
 	int rc = 0;
+	uint32_t btm_chan_idx = 0;
+
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-			adc_tm_data[btm_chan].low_thr_lsb_addr,
-			QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
+			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold lsb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].low_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
+		adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold msb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].high_thr_lsb_addr,
-		QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
+		adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+		QPNP_ADC_TM_THR_LSB_MASK(high_thr));
 	if (rc < 0) {
 		pr_err("high threshold lsb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].high_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
+		adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(high_thr));
 	if (rc < 0)
 		pr_err("high threshold msb setting failed\n");
 
-	pr_debug("client requested low:%d and high:%d\n",
-		chan_prop->low_thr, chan_prop->high_thr);
+	pr_debug("client requested high:%d and low:%d\n",
+		high_thr, low_thr);
 
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
+		uint32_t dt_index, uint32_t btm_chan)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
+	int high_thr = 0, low_thr = 0, rc = 0;
+
+
+	/* high_thr/low_thr starting point and reset the high_thr_set and
+		low_thr_set back to reset since the thresholds will be
+		recomputed */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		high_thr = client_info->high_thr_requested;
+		low_thr = client_info->low_thr_requested;
+		client_info->high_thr_set = false;
+		client_info->low_thr_set = false;
+	}
+
+	pr_debug("init threshold is high:%d and low:%d\n", high_thr, low_thr);
+
+	/* Find the min of high_thr and max of low_thr */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->high_thr_requested < high_thr)
+				high_thr = client_info->high_thr_requested;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->low_thr_requested > low_thr)
+				low_thr = client_info->low_thr_requested;
+
+		pr_debug("threshold compared is high:%d and low:%d\n",
+				client_info->high_thr_requested,
+				client_info->low_thr_requested);
+		pr_debug("current threshold is high:%d and low:%d\n",
+							high_thr, low_thr);
+	}
+
+	/* Check which of the high_thr and low_thr got set */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (high_thr == client_info->high_thr_requested)
+				client_info->high_thr_set = true;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (low_thr == client_info->low_thr_requested)
+				client_info->low_thr_set = true;
+	}
+
+	rc = qpnp_adc_tm_thr_update(chip, btm_chan, high_thr, low_thr);
+	if (rc < 0)
+		pr_err("setting chan:%d threshold failed\n", btm_chan);
+
+	pr_debug("threshold written is high:%d and low:%d\n",
+							high_thr, low_thr);
+
+	return 0;
+}
+
 static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
 			uint32_t btm_chan,
 			struct qpnp_vadc_chan_properties *chan_prop,
 			uint32_t amux_channel)
 {
 	int rc = 0, i = 0, chan_idx = 0;
-	bool chan_found = false;
+	bool chan_found = false, high_thr_set = false, low_thr_set = false;
 	u8 sensor_mask = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
 	while (i < chip->max_channels_available) {
 		if (chip->sensor[i].btm_channel_num == btm_chan) {
@@ -589,17 +761,22 @@
 	sensor_mask = 1 << chan_idx;
 	if (!chip->sensor[chan_idx].thermal_node) {
 		/* Update low and high notification thresholds */
-		rc = qpnp_adc_tm_thr_update(chip, btm_chan,
-				chan_prop);
+		rc = qpnp_adc_tm_manage_thresholds(chip, chan_idx,
+				btm_chan);
 		if (rc < 0) {
 			pr_err("setting chan:%d threshold failed\n", btm_chan);
 			return rc;
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_LOW_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		list_for_each_entry(client_info,
+				&chip->sensor[chan_idx].thr_list, list) {
+			if (client_info->high_thr_set == true)
+				high_thr_set = true;
+			if (client_info->low_thr_set == true)
+				low_thr_set = true;
+		}
+
+		if (low_thr_set) {
 			pr_debug("low sensor mask:%x with state:%d\n",
 					sensor_mask, chan_prop->state_request);
 			/* Enable low threshold's interrupt */
@@ -611,10 +788,7 @@
 			}
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_HIGH_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		if (high_thr_set) {
 			/* Enable high threshold's interrupt */
 			pr_debug("high sensor mask:%x\n", sensor_mask);
 			rc = qpnp_adc_tm_reg_update(chip,
@@ -760,8 +934,10 @@
 	int rc = 0, channel;
 	u8 sensor_mask = 0;
 
-	if (qpnp_adc_tm_is_valid(chip))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("invalid device\n");
 		return -ENODEV;
+	}
 
 	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
@@ -860,9 +1036,10 @@
 	struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
 	int64_t result = 0;
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
-	unsigned int reg, rc = 0, btm_channel_num;
+	unsigned int reg, rc = 0;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -870,11 +1047,17 @@
 	if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
 		return -EINVAL;
 
-	btm_channel_num = adc_tm_sensor->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm_sensor->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
@@ -934,7 +1117,8 @@
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
-	int rc = 0, btm_channel_num;
+	int rc = 0;
+	uint32_t btm_chan = 0, btm_chan_idx = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -967,11 +1151,17 @@
 	trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
 	trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
 
-	btm_channel_num = adc_tm->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
@@ -1015,20 +1205,25 @@
 
 static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* Battery therm's warm temperature translates to low voltage */
-	if (adc_tm->low_thr_notify) {
-		/* HIGH_STATE = WARM_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	/* Battery therm's cool temperature translates to high voltage */
-	if (adc_tm->high_thr_notify) {
-		/* LOW_STATE = COOL_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* Batt therm's warm temperature translates to low voltage */
+		if (client_info->notify_low_thr) {
+			/* HIGH_STATE = WARM_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_WARM_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_low_thr = false;
+		}
+
+		/* Batt therm's cool temperature translates to high voltage */
+		if (client_info->notify_high_thr) {
+			/* LOW_STATE = COOL_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_COOL_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_high_thr = false;
+		}
 	}
 
 	return;
@@ -1036,19 +1231,32 @@
 
 static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* For non batt therm clients */
-	if (adc_tm->low_thr_notify) {
-		pr_debug("notify kernel with low state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	if (adc_tm->high_thr_notify) {
-		pr_debug("notify kernel with high state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* For non batt therm clients */
+		if (client_info->notify_low_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with low state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_LOW_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_low_thr = false;
+			}
+		}
+
+		if (client_info->notify_high_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with high state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_HIGH_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_high_thr = false;
+			}
+		}
 	}
 
 	return;
@@ -1064,12 +1272,10 @@
 					NULL, "btm");
 		pr_debug("notifying uspace client\n");
 	} else {
-		if (adc_tm->btm_param->threshold_notification != NULL) {
-			if (adc_tm->scale_type == SCALE_RBATT_THERM)
-				notify_battery_therm(adc_tm);
-			else
-				notify_clients(adc_tm);
-		}
+		if (adc_tm->scale_type == SCALE_RBATT_THERM)
+			notify_battery_therm(adc_tm);
+		else
+			notify_clients(adc_tm);
 	}
 
 	return;
@@ -1083,6 +1289,7 @@
 	int rc = 0, sensor_mask = 0;
 	u8 thr_int_en = 0;
 	bool state = false;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -1097,24 +1304,29 @@
 
 	pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
 
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
 		/* low_thr (lower voltage) for higher temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							low_thr_int_chan_en;
+		thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
 		/* high_thr (higher voltage) for cooler temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							high_thr_int_chan_en;
+		thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	default:
 		return -EINVAL;
@@ -1128,7 +1340,10 @@
 	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
 	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
 	u8 sensor_mask = 0;
-	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
+	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+	uint32_t btm_chan_num = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -1190,7 +1405,6 @@
 				pr_err("high threshold int read failed\n");
 				goto fail;
 			}
-			chip->sensor[sensor_num].high_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding high voltage threshold which
@@ -1205,6 +1419,21 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->high_thr_set) {
+				client_info->high_thr_set = false;
+				client_info->notify_high_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_DISABLE;
+			}
+		}
 	}
 
 	if (adc_tm_low_enable) {
@@ -1233,7 +1462,6 @@
 				pr_err("low threshold int read failed\n");
 				goto fail;
 			}
-			chip->sensor[sensor_num].low_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding low voltage threshold which
@@ -1248,8 +1476,27 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->low_thr_set) {
+				/* mark the corresponding clients threshold
+					as not set */
+				client_info->low_thr_set = false;
+				client_info->notify_low_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_DISABLE;
+			}
+		}
 	}
 
+	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
+
 	if (adc_tm_high_enable || adc_tm_low_enable) {
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 			sensor_mask, false);
@@ -1359,8 +1606,10 @@
 	int rc = 0, i = 0;
 	bool chan_found = false;
 
-	if (qpnp_adc_tm_is_valid(chip))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("chip not valid\n");
 		return -ENODEV;
+	}
 
 	if (param->threshold_notification == NULL) {
 		pr_debug("No notification for high/low temp??\n");
@@ -1413,6 +1662,8 @@
 	adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
 			&chip->adc->amux_prop->chan_prop->low_thr,
 			&chip->adc->amux_prop->chan_prop->high_thr);
+	qpnp_adc_tm_add_to_list(chip, dt_index, param,
+				chip->adc->amux_prop->chan_prop);
 	chip->adc->amux_prop->chan_prop->tm_channel_select =
 				chip->sensor[dt_index].btm_channel_num;
 	chip->adc->amux_prop->chan_prop->timer_select =
@@ -1425,7 +1676,6 @@
 		goto fail_unlock;
 	}
 
-	chip->sensor[dt_index].btm_param = param;
 	chip->sensor[dt_index].scale_type = scale_type;
 
 fail_unlock:
@@ -1577,6 +1827,7 @@
 		goto fail;
 	}
 
+	chip->dev = &(spmi->dev);
 	chip->adc = adc_qpnp;
 
 	rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
@@ -1652,6 +1903,7 @@
 				pr_err("thermal device register failed.\n");
 		}
 		INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
+		INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
 		sen_idx++;
 	}
 	chip->max_channels_available = count_adc_channel_list;
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 1cf901e..8d9da6b 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -89,14 +89,30 @@
 }
 EXPORT_SYMBOL(sensor_get_id);
 
+static long get_min(struct sensor_info *sensor, long temp)
+{
+	long min = LONG_MIN;
+	struct sensor_threshold *pos, *var;
+
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW)
+			if (pos->temp < temp && pos->temp > min)
+				min = pos->temp;
+	}
+
+	return min;
+}
+
 static void __update_sensor_thresholds(struct sensor_info *sensor)
 {
-	int min = INT_MIN;
-	int max = INT_MAX;
+	long min = LONG_MIN;
+	long max = LONG_MAX;
+	long max_of_min = LONG_MIN;
+	long min_of_max = LONG_MAX;
 	struct sensor_threshold *pos, *var;
 	enum thermal_trip_type type;
 	int i;
-	unsigned long curr_temp;
+	long curr_temp;
 
 	for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
 		(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
@@ -106,36 +122,58 @@
 			sensor->max_idx = i;
 		if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
 			sensor->min_idx = i;
+		sensor->tz->ops->get_trip_temp(sensor->tz,
+			THERMAL_TRIP_CONFIGURABLE_LOW, &sensor->threshold_min);
+		sensor->tz->ops->get_trip_temp(sensor->tz,
+			THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
 	}
 
-	get_cpu();
 	sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
 	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
-		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
-				(pos->temp < (int)curr_temp))
-			if (pos->temp > min)
+		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) {
+			if (pos->temp > max_of_min)
+				max_of_min = pos->temp;
+			if (pos->temp < curr_temp && pos->temp > min)
 				min = pos->temp;
-		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
-				(pos->temp > (int)curr_temp))
-			if (pos->temp < max)
+		}
+		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) {
+			if (pos->temp < min_of_max)
+				min_of_max = pos->temp;
+			if (pos->temp > curr_temp && pos->temp < max)
 				max = pos->temp;
+		}
 	}
-	put_cpu();
+
+	pr_debug("sensor %d: min of max: %ld max of min: %ld\n",
+			sensor->sensor_id, max_of_min, min_of_max);
+
+	/* If we haven't found a max and min bounding the curr_temp,
+	 * use the min of max and max of min instead.
+	 */
+	if (max == LONG_MAX)
+		max = min_of_max;
+	if (min == LONG_MIN) {
+		min = get_min(sensor, max);
+		if (min == LONG_MIN)
+			min = max_of_min;
+	}
 
 	if (sensor->tz->ops->set_trip_temp) {
-		if (max != INT_MAX) {
+		if (max != sensor->threshold_max) {
 			sensor->tz->ops->set_trip_temp(sensor->tz,
 				sensor->max_idx, max);
 			sensor->threshold_max = max;
 		}
-		if (min != INT_MIN) {
+		if (min != sensor->threshold_min) {
 			sensor->tz->ops->set_trip_temp(sensor->tz,
 				sensor->min_idx, min);
 			sensor->threshold_min = min;
 		}
 	}
 
-	pr_debug("sensor %d, min: %d, max %d\n", sensor->sensor_id, min, max);
+	pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n",
+		sensor->sensor_id, curr_temp,
+		sensor->threshold_min, sensor->threshold_max);
 }
 
 static void sensor_update_work(struct work_struct *work)
@@ -151,7 +189,7 @@
  * Do NOT call sensor_set_trip from this function
  */
 int thermal_sensor_trip(struct thermal_zone_device *tz,
-		enum thermal_trip_type trip, unsigned long temp)
+		enum thermal_trip_type trip, long temp)
 {
 	struct sensor_threshold *pos, *var;
 	int ret = -ENODEV;
@@ -168,10 +206,10 @@
 			continue;
 		if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
 			(pos->temp <= tz->sensor.threshold_min) &&
-			(pos->temp >= (int) temp)) ||
+			(pos->temp >= temp)) ||
 			((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
 				(pos->temp >= tz->sensor.threshold_max) &&
-				(pos->temp <= (int)temp))) {
+				(pos->temp <= temp))) {
 			pos->notify(trip, temp, pos->data);
 		}
 	}
@@ -235,29 +273,6 @@
 }
 EXPORT_SYMBOL(sensor_cancel_trip);
 
-static int sensor_get_trip_temp(struct thermal_zone_device *tz,
-		int type, unsigned long *temp)
-{
-	struct sensor_info *sensor = get_sensor(tz->id);
-
-	if (!sensor)
-		return -EFAULT;
-
-	switch (type) {
-	case THERMAL_TRIP_CONFIGURABLE_HI:
-		*temp = tz->sensor.threshold_max;
-		break;
-	case THERMAL_TRIP_CONFIGURABLE_LOW:
-		*temp = tz->sensor.threshold_min;
-		break;
-	default:
-		tz->ops->get_trip_temp(tz, type, temp);
-		break;
-	}
-
-	return 0;
-}
-
 static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
 {
 	struct thermal_zone_device *tz = (struct thermal_zone_device *)data;
@@ -310,7 +325,7 @@
 	sensor->sensor_id = tz->id;
 	sensor->tz = tz;
 	sensor->threshold_min = 0;
-	sensor->threshold_max = INT_MAX;
+	sensor->threshold_max = LONG_MAX;
 	sensor->max_idx = -1;
 	sensor->min_idx = -1;
 	mutex_init(&sensor->lock);
@@ -511,7 +526,7 @@
 	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 		return -EINVAL;
 
-	ret = sensor_get_trip_temp(tz, trip, &temperature);
+	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
 
 	if (ret)
 		return ret;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f43affb..60d7119 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -201,6 +201,7 @@
 	bool			lpm_irq_seen;
 	struct delayed_work	resume_work;
 	struct work_struct	restart_usb_work;
+	struct work_struct	usb_block_reset_work;
 	struct dwc3_charger	charger;
 	struct usb_phy		*otg_xceiv;
 	struct delayed_work	chg_work;
@@ -1495,6 +1496,11 @@
 	case DWC3_CONTROLLER_ERROR_EVENT:
 		dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
 		dwc3_msm_dump_phy_info(mdwc);
+		/*
+		 * schedule work for doing block reset for recovery from erratic
+		 * error event.
+		 */
+		queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
 		break;
 	case DWC3_CONTROLLER_RESET_EVENT:
 		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
@@ -1537,6 +1543,16 @@
 	dwc3_msm_dbm_soft_reset(mdwc, 0);
 }
 
+static void dwc3_block_reset_usb_work(struct work_struct *w)
+{
+	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+						usb_block_reset_work);
+
+	dev_dbg(mdwc->dev, "%s\n", __func__);
+
+	dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
+}
+
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
 {
 	u32 chg_ctrl;
@@ -2692,6 +2708,7 @@
 	INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
 	INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
 	INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
+	INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
 	INIT_WORK(&mdwc->id_work, dwc3_id_work);
 	INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
 	init_completion(&mdwc->ext_chg_wait);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index e912e86..9599936 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -24,6 +24,7 @@
 #include "io.h"
 #include "xhci.h"
 
+#define VBUS_REG_CHECK_DELAY	(msecs_to_jiffies(1000))
 #define MAX_INVALID_CHRGR_RETRY 3
 static int max_chgr_retry_count = MAX_INVALID_CHRGR_RETRY;
 module_param(max_chgr_retry_count, int, S_IRUGO | S_IWUSR);
@@ -336,13 +337,13 @@
 		dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
 					__func__, gadget->name);
 		otg->gadget = gadget;
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	} else {
 		if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
 			dwc3_otg_start_peripheral(otg, 0);
 			otg->gadget = NULL;
 			otg->phy->state = OTG_STATE_UNDEFINED;
-			schedule_work(&dotg->sm_work);
+			queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 		} else {
 			otg->gadget = NULL;
 		}
@@ -367,7 +368,7 @@
 	 * STOP chg_det as part of !BSV handling would reset the chg_det flags
 	 */
 	if (test_bit(B_SESS_VLD, &dotg->inputs))
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 }
 
 /**
@@ -406,7 +407,7 @@
 
 	/* Flush processing any pending events before handling new ones */
 	if (init)
-		flush_work(&dotg->sm_work);
+		flush_delayed_work(&dotg->sm_work);
 
 	if (event == DWC3_EVENT_PHY_RESUME) {
 		if (!pm_runtime_status_suspended(phy->dev)) {
@@ -453,15 +454,16 @@
 
 		if (!init) {
 			init = true;
-			if (!work_busy(&dotg->sm_work))
-				schedule_work(&dotg->sm_work);
+			if (!work_busy(&dotg->sm_work.work))
+				queue_delayed_work(system_nrt_wq,
+							&dotg->sm_work, 0);
 
 			complete(&dotg->dwc3_xcvr_vbus_init);
 			dev_dbg(phy->dev, "XCVR: BSV init complete\n");
 			return;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	}
 }
 
@@ -610,7 +612,7 @@
 			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 
 		ret = IRQ_HANDLED;
 
@@ -671,10 +673,12 @@
  */
 static void dwc3_otg_sm_work(struct work_struct *w)
 {
-	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
 	struct usb_phy *phy = dotg->otg.phy;
 	struct dwc3_charger *charger = dotg->charger;
 	bool work = 0;
+	int ret = 0;
+	unsigned long delay = 0;
 
 	pm_runtime_resume(phy->dev);
 	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
@@ -817,10 +821,23 @@
 		if (test_bit(ID, &dotg->inputs)) {
 			dev_dbg(phy->dev, "id\n");
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		} else {
 			phy->state = OTG_STATE_A_HOST;
-			if (dwc3_otg_start_host(&dotg->otg, 1)) {
+			ret = dwc3_otg_start_host(&dotg->otg, 1);
+			if ((ret == -EPROBE_DEFER) &&
+						dotg->vbus_retry_count < 3) {
+				/*
+				 * Get regulator failed as regulator driver is
+				 * not up yet. Will try to start host after 1sec
+				 */
+				phy->state = OTG_STATE_A_IDLE;
+				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
+				delay = VBUS_REG_CHECK_DELAY;
+				work = 1;
+				dotg->vbus_retry_count++;
+			} else if (ret) {
 				/*
 				 * Probably set_host was not called yet.
 				 * We will re-try as soon as it will be called
@@ -839,6 +856,7 @@
 			dev_dbg(phy->dev, "id\n");
 			dwc3_otg_start_host(&dotg->otg, 0);
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		}
 		break;
@@ -849,7 +867,7 @@
 	}
 
 	if (work)
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
 }
 
 
@@ -973,7 +991,7 @@
 	dotg->otg.phy->state = OTG_STATE_UNDEFINED;
 
 	init_completion(&dotg->dwc3_xcvr_vbus_init);
-	INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+	INIT_DELAYED_WORK(&dotg->sm_work, dwc3_otg_sm_work);
 
 	ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
 				"dwc3_otg", dotg);
@@ -988,7 +1006,7 @@
 	return 0;
 
 err3:
-	cancel_work_sync(&dotg->sm_work);
+	cancel_delayed_work_sync(&dotg->sm_work);
 	usb_set_transceiver(NULL);
 err2:
 	kfree(dotg->otg.phy);
@@ -1013,7 +1031,7 @@
 	if (dotg) {
 		if (dotg->charger)
 			dotg->charger->start_detection(dotg->charger, false);
-		cancel_work_sync(&dotg->sm_work);
+		cancel_delayed_work_sync(&dotg->sm_work);
 		usb_set_transceiver(NULL);
 		pm_runtime_put(dwc->dev);
 		free_irq(dotg->irq, dotg);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 7adf874..3a75b0a 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -41,7 +41,7 @@
 	struct dwc3		*dwc;
 	void __iomem		*regs;
 	struct regulator	*vbus_otg;
-	struct work_struct	sm_work;
+	struct delayed_work	sm_work;
 	struct dwc3_charger	*charger;
 	struct dwc3_ext_xceiv	*ext_xceiv;
 #define ID		0
@@ -51,6 +51,7 @@
 	struct completion	dwc3_xcvr_vbus_init;
 	int			host_bus_suspend;
 	int			charger_retry_count;
+	int			vbus_retry_count;
 };
 
 /**
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index aaa22f3..8588ffb 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2617,10 +2617,13 @@
 		}
 	}
 
+	/*
+	 * Notify suspend only to gadget driver, but not resume. Resume is
+	 * notified as part of wakeup event in dwc3_gadget_wakeup_interrupt().
+	 */
 	if (next == DWC3_LINK_STATE_U0) {
 		if (dwc->link_state == DWC3_LINK_STATE_U3) {
 			dbg_event(0xFF, "RESUME", 0);
-			dwc->gadget_driver->resume(&dwc->gadget);
 		}
 	} else if (next == DWC3_LINK_STATE_U3) {
 		dbg_event(0xFF, "SUSPEND", 0);
@@ -2656,9 +2659,6 @@
 	dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
 
 	dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
-
-	panic("DWC3 Erratic error\n");
-
 }
 
 static void dwc3_gadget_interrupt(struct dwc3 *dwc,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index bbb206d..6765078 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1478,7 +1478,11 @@
 		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
 		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
 
-	ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
+	if (rndis->ethaddr[0])
+		ret = gether_setup_name(c->cdev->gadget, NULL, "rndis");
+	else
+		ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr,
+								"rndis");
 	if (ret) {
 		pr_err("%s: gether_setup failed\n", __func__);
 		return ret;
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_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_ether.c b/drivers/usb/gadget/u_ether.c
index 325c2b5..9e789c5 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -553,6 +553,7 @@
 				}
 
 				new_req->length = length;
+				new_req->complete = tx_complete;
 				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
 				switch (retval) {
 				default:
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/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d102c22..5d58f16 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -342,7 +342,7 @@
 
 #define HSIC_DBG1_REG		0x38
 
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{   /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
 			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
@@ -359,6 +359,8 @@
 {
 	int ret = 0;
 	int none_vol, min_vol, max_vol;
+	u32 tmp[3];
+	int len = 0;
 
 	if (!mehci->hsic_vddcx) {
 		mehci->vdd_type = VDDCX_CORNER;
@@ -373,6 +375,22 @@
 			}
 			mehci->vdd_type = VDDCX;
 		}
+
+		if (mehci->dev->of_node) {
+			of_get_property(mehci->dev->of_node,
+					"hsic,vdd-voltage-level",
+					&len);
+			if (len == sizeof(tmp)) {
+				of_property_read_u32_array(mehci->dev->of_node,
+						"hsic,vdd-voltage-level",
+						tmp, len/sizeof(*tmp));
+				vdd_val[mehci->vdd_type][VDD_NONE] = tmp[0];
+				vdd_val[mehci->vdd_type][VDD_MIN] = tmp[1];
+				vdd_val[mehci->vdd_type][VDD_MAX] = tmp[2];
+			} else {
+				dev_dbg(mehci->dev, "Use default vdd config\n");
+			}
+		}
 	}
 
 	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 0aecaad..dd04f49 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -40,6 +40,7 @@
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 #include <linux/debugfs.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -76,6 +77,7 @@
 	int					wakeup_int_cnt;
 	bool					wakeup_irq_enabled;
 	int					wakeup_irq;
+	enum usb_vdd_type			vdd_type;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -96,26 +98,87 @@
 #define HSUSB_PHY_1P8_VOL_MAX		1800000 /* uV */
 #define HSUSB_PHY_1P8_HPM_LOAD		50000	/* uA */
 
+#define HSUSB_PHY_VDD_DIG_VOL_NONE	0	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MIN	1045000	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MAX	1320000	/* uV */
 #define HSUSB_PHY_VDD_DIG_LOAD		49360	/* uA */
 
+#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
+enum hsusb_vdd_value {
+	VDD_MIN_NONE = 0,
+	VDD_MIN_P50,
+	VDD_MIN_P75,
+	VDD_MIN_OP,
+	VDD_MAX_OP,
+	VDD_VAL_MAX_OP,
+};
+
+static int hsusb_vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX_OP] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_MIN_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P50]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P75]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_OP]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX_OP]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_MIN_NONE]	= HSUSB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN_P50]	= HSUSB_PHY_SUSP_DIG_VOL_P50,
+			[VDD_MIN_P75]	= HSUSB_PHY_SUSP_DIG_VOL_P75,
+			[VDD_MIN_OP]	= HSUSB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX_OP]	= HSUSB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
+
 static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+	u32 tmp[5];
+	int len = 0;
 
-	if (!init)
+	if (!init) {
+		none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+		max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 		goto disable_reg;
-
-	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "HSUSB_VDDCX");
-	if (IS_ERR(mhcd->hsusb_vddcx)) {
-		dev_err(mhcd->dev, "unable to get ehci vddcx\n");
-		return PTR_ERR(mhcd->hsusb_vddcx);
 	}
 
-	ret = regulator_set_voltage(mhcd->hsusb_vddcx,
-			HSUSB_PHY_VDD_DIG_VOL_MIN,
-			HSUSB_PHY_VDD_DIG_VOL_MAX);
+	mhcd->vdd_type = VDDCX_CORNER;
+	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "hsusb_vdd_dig");
+	if (IS_ERR(mhcd->hsusb_vddcx)) {
+		mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev,
+							"HSUSB_VDDCX");
+		if (IS_ERR(mhcd->hsusb_vddcx)) {
+			dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+			return PTR_ERR(mhcd->hsusb_vddcx);
+		}
+		mhcd->vdd_type = VDDCX;
+	}
+
+	if (mhcd->dev->of_node) {
+		of_get_property(mhcd->dev->of_node,
+				"qcom,vdd-voltage-level",
+				&len);
+		if (len == sizeof(tmp)) {
+			of_property_read_u32_array(mhcd->dev->of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len/sizeof(*tmp));
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE] = tmp[0];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50] = tmp[1];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75] = tmp[2];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP] = tmp[3];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP] = tmp[4];
+		} else {
+			dev_dbg(mhcd->dev, "Use default vdd config\n");
+		}
+	}
+
+	none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+	min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
+	max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mhcd->dev, "unable to set the voltage"
 				"for ehci vddcx\n");
@@ -143,8 +206,7 @@
 reg_enable_err:
 	regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
 reg_optimum_mode_err:
-	regulator_set_voltage(mhcd->hsusb_vddcx, 0,
-				HSUSB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mhcd->hsusb_vddcx, none_vol, max_vol);
 	return ret;
 
 }
@@ -194,24 +256,22 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
-#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
 static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
 {
 	struct msm_usb_host_platform_data *pdata;
-	int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+	int max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 	int min_vol;
 	int ret;
 
 	pdata = mhcd->dev->platform_data;
 
 	if (high)
-		min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
 	else if (pdata && pdata->dock_connect_irq &&
 			!irq_read_line(pdata->dock_connect_irq))
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75];
 	else
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50];
 
 	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f71f54c..4cf4703 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -3607,6 +3607,9 @@
 	case POWER_SUPPLY_PROP_TYPE:
 		val->intval = psy->type;
 		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = motg->usbin_health;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -3637,6 +3640,9 @@
 	case POWER_SUPPLY_PROP_TYPE:
 		psy->type = val->intval;
 		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		motg->usbin_health = val->intval;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -3649,6 +3655,7 @@
 						enum power_supply_property psp)
 {
 	switch (psp) {
+	case POWER_SUPPLY_PROP_HEALTH:
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
@@ -3666,6 +3673,7 @@
 };
 
 static enum power_supply_property otg_pm_power_props_usb[] = {
+	POWER_SUPPLY_PROP_HEALTH,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 9ca3461..65cca0e 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -65,6 +65,7 @@
 				panel_data);
 
 	if (enable) {
+		dsi_ctrl_gpio_request(ctrl_pdata);
 		mdss_dsi_panel_reset(pdata, 1);
 
 		rc = dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
@@ -82,6 +83,7 @@
 					ctrl_pdata->off_cmds.cmd_cnt);
 
 		mdss_dsi_panel_reset(pdata, 0);
+		dsi_ctrl_gpio_free(ctrl_pdata);
 	}
 	return rc;
 }
@@ -139,117 +141,37 @@
 				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct device_node *np = pdev->dev.of_node;
-	int rc = 0, i = 0;
-	u32 tmp[9];
 
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(np,
 		"qcom,platform-enable-gpio", 0);
 
-	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
 		pr_err("%s:%d, Disp_en gpio not specified\n",
 						__func__, __LINE__);
-	} else {
-		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
-		if (rc) {
-			pr_err("request reset gpio failed, rc=%d\n",
-			       rc);
-			gpio_free(ctrl_pdata->disp_en_gpio);
-			return -ENODEV;
-		}
-	}
 
+	ctrl_pdata->disp_te_gpio = -1;
 	if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
 		ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
 						"qcom,platform-te-gpio", 0);
-		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio))
 			pr_err("%s:%d, Disp_te gpio not specified\n",
 							__func__, __LINE__);
-		} else {
-			rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
-			if (rc) {
-				pr_err("request TE gpio failed, rc=%d\n",
-								       rc);
-				gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-			rc = gpio_tlmm_config(GPIO_CFG(
-					ctrl_pdata->disp_te_gpio, 1,
-					GPIO_CFG_INPUT,
-					GPIO_CFG_PULL_DOWN,
-					GPIO_CFG_2MA),
-					GPIO_CFG_ENABLE);
-
-			if (rc) {
-				pr_err("%s: unable to config tlmm = %d\n",
-					__func__, ctrl_pdata->disp_te_gpio);
-				gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-
-			rc = gpio_direction_input(ctrl_pdata->disp_te_gpio);
-			if (rc) {
-				pr_err("set_direction for disp_en gpio failed, rc=%d\n",
-								       rc);
-				gpio_free(ctrl_pdata->disp_te_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-					gpio_free(ctrl_pdata->disp_en_gpio);
-				return -ENODEV;
-			}
-			pr_debug("%s: te_gpio=%d\n", __func__,
-					ctrl_pdata->disp_te_gpio);
-		}
 	}
 
-	rc = of_property_read_u32_array(np,
-		"qcom,platform-reset-sequence", tmp, MDSS_DSI_RST_SEQ_LEN);
-	if (rc)
-		pr_err("%s:%d, unable to read gpio reset sequence\n",
-						__func__, __LINE__);
-	else
-		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i)
-			ctrl_pdata->rst_seq[i] = tmp[i];
-
 	ctrl_pdata->rst_gpio = of_get_named_gpio(np,
 					"qcom,platform-reset-gpio", 0);
-	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+	if (!gpio_is_valid(ctrl_pdata->rst_gpio))
 		pr_err("%s:%d, reset gpio not specified\n",
 						__func__, __LINE__);
-	} else {
-		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
-		if (rc) {
-			pr_err("request reset gpio failed, rc=%d\n",
-				rc);
-			gpio_free(ctrl_pdata->rst_gpio);
-			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-				gpio_free(ctrl_pdata->disp_en_gpio);
-			if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
-				gpio_free(ctrl_pdata->disp_te_gpio);
-			return -ENODEV;
-		}
-	}
 
+	ctrl_pdata->mode_gpio = -1;
 	if (ctrl_pdata->panel_data.panel_info.mode_gpio_state !=
 						MODE_GPIO_NOT_VALID) {
 		ctrl_pdata->mode_gpio = of_get_named_gpio(np,
 						"qcom,platform-mode-gpio", 0);
-		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio))
 			pr_info("%s:%d, reset gpio not specified\n",
 							__func__, __LINE__);
-		} else {
-			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
-			if (rc) {
-				pr_err("request panel mode gpio failed,rc=%d\n",
-									rc);
-				gpio_free(ctrl_pdata->mode_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-					gpio_free(ctrl_pdata->disp_en_gpio);
-				if (gpio_is_valid(ctrl_pdata->rst_gpio))
-					gpio_free(ctrl_pdata->rst_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
-					gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-		}
 	}
 	return 0;
 }
@@ -268,15 +190,81 @@
 		module_power->vreg_config = NULL;
 	}
 	module_power->num_vreg = 0;
+}
 
-	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-		gpio_free(ctrl_pdata->disp_en_gpio);
-	if (gpio_is_valid(ctrl_pdata->rst_gpio))
-		gpio_free(ctrl_pdata->rst_gpio);
+int dsi_ctrl_gpio_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int rc = 0;
+
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
+		if (rc)
+			goto gpio_request_err4;
+
+		ctrl_pdata->disp_en_gpio_requested = 1;
+	}
+
+	if (gpio_is_valid(ctrl_pdata->rst_gpio)) {
+		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+		if (rc)
+			goto gpio_request_err3;
+
+		ctrl_pdata->rst_gpio_requested = 1;
+	}
+
+	if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+		rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
+		if (rc)
+			goto gpio_request_err2;
+
+		ctrl_pdata->disp_te_gpio_requested = 1;
+	}
+
+	if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+		rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+		if (rc)
+			goto gpio_request_err1;
+
+		ctrl_pdata->mode_gpio_requested = 1;
+	}
+
+	return rc;
+
+gpio_request_err1:
 	if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
 		gpio_free(ctrl_pdata->disp_te_gpio);
-	if (gpio_is_valid(ctrl_pdata->mode_gpio))
+gpio_request_err2:
+	if (gpio_is_valid(ctrl_pdata->rst_gpio))
+		gpio_free(ctrl_pdata->rst_gpio);
+gpio_request_err3:
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+		gpio_free(ctrl_pdata->disp_en_gpio);
+gpio_request_err4:
+	ctrl_pdata->disp_en_gpio_requested = 0;
+	ctrl_pdata->rst_gpio_requested = 0;
+	ctrl_pdata->disp_te_gpio_requested = 0;
+	ctrl_pdata->mode_gpio_requested = 0;
+	return rc;
+}
+
+void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	if (ctrl_pdata->disp_en_gpio_requested) {
+		gpio_free(ctrl_pdata->disp_en_gpio);
+		ctrl_pdata->disp_en_gpio_requested = 0;
+	}
+	if (ctrl_pdata->rst_gpio_requested) {
+		gpio_free(ctrl_pdata->rst_gpio);
+		ctrl_pdata->rst_gpio_requested = 0;
+	}
+	if (ctrl_pdata->disp_te_gpio_requested) {
+		gpio_free(ctrl_pdata->disp_te_gpio);
+		ctrl_pdata->disp_te_gpio_requested = 0;
+	}
+	if (ctrl_pdata->mode_gpio_requested) {
 		gpio_free(ctrl_pdata->mode_gpio);
+		ctrl_pdata->mode_gpio_requested = 0;
+	}
 }
 
 static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index a554856..e15f640 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -70,6 +70,10 @@
 int dsi_ctrl_config_init(struct platform_device *pdev,
 				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
+int dsi_ctrl_gpio_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
+void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
 struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val);
 
 int mdp3_panel_get_boot_cfg(void);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 8a5f1ee..55037e3 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -35,6 +35,9 @@
 #include <linux/uaccess.h>
 #include <linux/file.h>
 #include <linux/msm_kgsl.h>
+#include <linux/major.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
 
 #include <mach/board.h>
 #include <mach/clk.h>
@@ -583,6 +586,41 @@
 	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;
@@ -658,6 +696,9 @@
 			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;
@@ -1594,6 +1635,45 @@
 	}
 }
 
+int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	int rc;
+	u32 offsets[2];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+				"qcom,memblock-reserve", offsets, 2);
+
+	if (rc) {
+		pr_err("fail to get memblock-reserve property\n");
+		return rc;
+	}
+
+	if (mdp3_res->splash_mem_addr != offsets[0])
+		rc = -EINVAL;
+
+	mdp3_res->splash_mem_addr = offsets[0];
+	mdp3_res->splash_mem_size = offsets[1];
+
+	pr_debug("memaddr=%x size=%x\n", mdp3_res->splash_mem_addr,
+		mdp3_res->splash_mem_size);
+
+	return rc;
+}
+
+void mdp3_release_splash_memory(void)
+{
+	/* Give back the reserved memory to the system */
+	if (mdp3_res->splash_mem_addr) {
+		pr_debug("mdp3_release_splash_memory\n");
+		memblock_free(mdp3_res->splash_mem_addr,
+				mdp3_res->splash_mem_size);
+		free_bootmem_late(mdp3_res->splash_mem_addr,
+				mdp3_res->splash_mem_size);
+		mdp3_res->splash_mem_addr = 0;
+	}
+}
+
 struct mdp3_dma *mdp3_get_dma_pipe(int capability)
 {
 	int i;
@@ -1684,6 +1764,8 @@
 		rc = (status == 0x080000);
 	}
 
+	mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_S_IBUF_ADDR);
+
 	mdp3_clk_update(MDP3_CLK_AHB, 0);
 	mdp3_clk_update(MDP3_CLK_CORE, 0);
 	return rc;
@@ -1717,12 +1799,6 @@
 		goto splash_on_err;
 	}
 
-	rc = mdp3_continuous_splash_copy(pdata);
-	if (rc) {
-		pr_err("fail to copy continuous splash image\n");
-		goto splash_on_err;
-	}
-
 	mdp3_irq_register();
 
 	if (pdata->event_handler) {
@@ -1765,6 +1841,14 @@
 	return rc;
 }
 
+static int mdp3_debug_dump_stats(void *data, char *buf, int len)
+{
+	int total = 0;
+	total = scnprintf(buf, len,"underrun: %08u\n",
+			mdp3_res->underrun_cnt);
+	return total;
+}
+
 static void mdp3_debug_enable_clock(int on)
 {
 	if (on)
@@ -1784,7 +1868,7 @@
 
 	mdss_res = mdata;
 
-	mdata->debug_inf.debug_dump_stats = NULL;
+	mdata->debug_inf.debug_dump_stats = mdp3_debug_dump_stats;
 	mdata->debug_inf.debug_enable_clock = mdp3_debug_enable_clock;
 
 	rc = mdss_debugfs_init(mdata);
@@ -1806,6 +1890,14 @@
 	}
 }
 
+static void mdp3_dma_underrun_intr_handler(int type, void *arg)
+{
+	mdp3_res->underrun_cnt++;
+	pr_debug("display underrun detected count=%d\n",
+			mdp3_res->underrun_cnt);
+}
+
+
 static int mdp3_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -1816,6 +1908,11 @@
 	.fb_stride = mdp3_fb_stride,
 	};
 
+	struct mdp3_intr_cb underrun_cb = {
+		.cb = mdp3_dma_underrun_intr_handler,
+		.data = NULL,
+	};
+
 	if (!pdev->dev.of_node) {
 		pr_err("MDP driver only supports device tree probe\n");
 		return -ENOTSUPP;
@@ -1863,6 +1960,11 @@
 	if (rc)
 		pr_err("unable to register mdp instance\n");
 
+	rc = mdp3_set_intr_callback(MDP3_INTR_LCDC_UNDERFLOW,
+					&underrun_cb);
+	if (rc)
+		pr_err("unable to configure interrupt callback\n");
+
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdp3_res_deinit();
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 2f73c42..4480c20 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -144,11 +144,14 @@
 	u32 irq_ref_count[MDP3_MAX_INTR];
 	u32 irq_mask;
 	struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
+	u32 underrun_cnt;
 
 	int irq_registered;
 
 	struct early_suspend suspend_handler;
 	struct mdss_panel_cfg pan_cfg;
+	u32 splash_mem_addr;
+	u32 splash_mem_size;
 };
 
 struct mdp3_img_data {
@@ -181,6 +184,8 @@
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
 void mdp3_free(void);
+int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
+void mdp3_release_splash_memory(void);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index bf5b643..9c909bf 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -481,12 +481,13 @@
 			pr_err("fail to start the MDP display interface\n");
 			goto on_error;
 		}
+	} else {
+		mdp3_session->first_commit = true;
 	}
 
 on_error:
 	if (!rc)
 		mdp3_session->status = 1;
-
 	mutex_unlock(&mdp3_session->lock);
 	return rc;
 }
@@ -557,6 +558,56 @@
 	return 0;
 }
 
+static int mdp3_ctrl_reset_cmd(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session;
+	struct mdp3_dma *mdp3_dma;
+	struct mdss_panel_data *panel;
+	struct mdp3_vsync_notification vsync_client;
+
+	pr_debug("mdp3_ctrl_reset_cmd\n");
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
+		!mdp3_session->intf) {
+		pr_err("mdp3_ctrl_reset no device");
+		return -ENODEV;
+	}
+
+	panel = mdp3_session->panel;
+	mdp3_dma = mdp3_session->dma;
+	mutex_lock(&mdp3_session->lock);
+
+	vsync_client = mdp3_dma->vsync_client;
+
+	rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
+	if (rc) {
+		pr_err("fail to stop the MDP3 dma\n");
+		goto reset_error;
+	}
+
+	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
+	if (rc) {
+		pr_err("fail to attach dma iommu\n");
+		goto reset_error;
+	}
+
+	mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
+	mdp3_ctrl_dma_init(mfd, mdp3_dma);
+
+	if (vsync_client.handler)
+		mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
+
+	if (mfd->fbi->screen_base)
+		rc = mdp3_dma->start(mdp3_dma, mdp3_session->intf);
+	else
+		mdp3_session->first_commit = true;
+
+reset_error:
+	mutex_unlock(&mdp3_session->lock);
+	return rc;
+}
+
 static int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
 {
 	int rc = 0;
@@ -573,11 +624,18 @@
 		return -ENODEV;
 	}
 
+	if (mfd->panel.type == MIPI_CMD_PANEL) {
+		rc = mdp3_ctrl_reset_cmd(mfd);
+		return rc;
+	}
+
 	panel = mdp3_session->panel;
 	mdp3_dma = mdp3_session->dma;
 	mutex_lock(&mdp3_session->lock);
 
 	vsync_client = mdp3_dma->vsync_client;
+	if (panel && panel->set_backlight)
+		panel->set_backlight(panel, 0);
 
 	rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
 	if (rc) {
@@ -633,6 +691,8 @@
 
 	if (mfd->fbi->screen_base)
 		rc = mdp3_dma->start(mdp3_dma, mdp3_session->intf);
+	else
+		mdp3_session->first_commit = true;
 
 reset_error:
 	mutex_unlock(&mdp3_session->lock);
@@ -742,11 +802,15 @@
 	return rc;
 }
 
-static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd)
+static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
+					struct mdp_display_commit *cmt_data)
 {
 	struct mdp3_session_data *mdp3_session;
 	struct mdp3_img_data *data;
+	struct mdss_panel_info *panel_info = mfd->panel_info;
 	int rc = 0;
+	bool reset_done = false;
+	struct mdss_panel_data *panel;
 
 	if (!mfd || !mfd->mdp.private1)
 		return -EINVAL;
@@ -755,11 +819,18 @@
 	if (!mdp3_session || !mdp3_session->dma)
 		return -EINVAL;
 
+	if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) {
+		pr_debug("no buffer in queue yet\n");
+		return -EPERM;
+	}
+
+	panel = mdp3_session->panel;
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
 		mdp3_ctrl_reset(mfd);
-		mdp3_free();
+		reset_done = true;
 	}
+	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -781,6 +852,15 @@
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
 		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
+
+	if (mdp3_session->first_commit) {
+		/*wait for one frame time to ensure frame is sent to panel*/
+		msleep(1000 / panel_info->mipi.frame_rate);
+		mdp3_session->first_commit = false;
+	}
+	if (reset_done && (panel && panel->set_backlight))
+		panel->set_backlight(panel, panel->panel_info.bl_max);
+
 	mutex_unlock(&mdp3_session->lock);
 
 	mdss_fb_update_notify_update(mfd);
@@ -794,6 +874,7 @@
 	struct mdp3_session_data *mdp3_session;
 	u32 offset;
 	int bpp;
+	struct mdss_panel_info *panel_info = mfd->panel_info;
 
 	pr_debug("mdp3_ctrl_pan_display\n");
 	if (!mfd || !mfd->mdp.private1)
@@ -805,9 +886,9 @@
 
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_off(mfd);
-		mdp3_ctrl_on(mfd);
+		mdp3_ctrl_reset(mfd);
 	}
+	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -836,6 +917,13 @@
 		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
 		mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
 	}
+
+	if (mdp3_session->first_commit) {
+		/*wait for one frame time to ensure frame is sent to panel*/
+		msleep(1000 / panel_info->mipi.frame_rate);
+		mdp3_session->first_commit = false;
+	}
+
 pan_error:
 	mutex_unlock(&mdp3_session->lock);
 }
@@ -1219,7 +1307,8 @@
 	if (!mdp3_session->dma->config_lut)
 		return -EINVAL;
 
-	if (cmap->start + cmap->len > MDP_LUT_SIZE) {
+	if (cmap->start > MDP_LUT_SIZE || cmap->len > MDP_LUT_SIZE ||
+			(cmap->start + cmap->len > MDP_LUT_SIZE)) {
 		pr_err("mdp3_ctrl_lut_update invalid arguments\n");
 		return  -EINVAL;
 	}
@@ -1358,8 +1447,13 @@
 	struct mdp3_session_data *mdp3_session = NULL;
 	u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
 	int rc;
+	int splash_mismatch = 0;
 
 	pr_debug("mdp3_ctrl_init\n");
+	rc = mdp3_parse_dt_splash(mfd);
+	if (rc)
+		splash_mismatch = 1;
+
 	mdp3_interface->on_fnc = mdp3_ctrl_on;
 	mdp3_interface->off_fnc = mdp3_ctrl_off;
 	mdp3_interface->do_histogram = NULL;
@@ -1404,7 +1498,7 @@
 	mdp3_session->dma->output_config.out_sel = intf_type;
 	mdp3_session->mfd = mfd;
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
-	mdp3_session->status = 0;
+	mdp3_session->status = mdp3_session->intf->active;
 	mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 	mdp3_bufq_init(&mdp3_session->bufq_in);
 	mdp3_bufq_init(&mdp3_session->bufq_out);
@@ -1434,6 +1528,11 @@
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
+	if (splash_mismatch) {
+		pr_err("splash memory mismatch, stop splash\n");
+		mdp3_ctrl_off(mfd);
+	}
+
 init_done:
 	if (IS_ERR_VALUE(rc))
 		kfree(mdp3_session);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index eb32797..7c4f6ac 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -51,6 +51,7 @@
 	struct mutex histo_lock;
 	int lut_sel;
 	int cc_vect_sel;
+	bool first_commit;
 };
 
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 5ed89e4..89f3e27 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -159,6 +159,7 @@
 		.data = dma,
 	};
 
+
 	struct mdp3_intr_cb hist_cb = {
 		.cb = mdp3_hist_done_intr_handler,
 		.data = dma,
@@ -292,17 +293,13 @@
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_OUT_XY, dma_p_out_xy);
 
-	/*
-	 * NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
-	 * the default 16 for MDP hang issue workaround
-	 */
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
-
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x40);
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
 	mdp3_dma_sync_config(dma, source_config);
 
+	mdp3_irq_enable(MDP3_INTR_LCDC_UNDERFLOW);
 	mdp3_dma_callback_setup(dma);
 	return 0;
 }
@@ -829,6 +826,7 @@
 
 	mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_VSYNC |
 					MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
+	mdp3_irq_disable(MDP3_INTR_LCDC_UNDERFLOW);
 
 	init_completion(&dma->dma_comp);
 	dma->vsync_client.handler = NULL;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index e1f2d10..8f6168a 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -54,6 +54,7 @@
 	[MDP_YCRYCB_H2V1] = true,
 	[MDP_Y_CBCR_H2V1] = true,
 	[MDP_Y_CRCB_H2V1] = true,
+	[MDP_BGRX_8888] = true,
 };
 
 #define MAX_LIST_WINDOW 16
@@ -495,9 +496,13 @@
 {
 	int dst_h, src_w, i;
 	uint32_t mdp_op = blit_op->mdp_op;
+	void *src_p0 = blit_op->src.p0;
+	void *src_p1 = blit_op->src.p1;
+	void *dst_p0 = blit_op->dst.p0;
 
 	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 */
@@ -526,8 +531,11 @@
 		/* this is for a remainder update */
 		dst_h -= 16;
 		src_w -= blit_op->src.roi.width;
-		/* restore mdp_op since MDPOP_ASCALE have been cleared */
+		/* restore parameters that may have been overwritten */
 		blit_op->mdp_op = mdp_op;
+		blit_op->src.p0 = src_p0;
+		blit_op->src.p1 = src_p1;
+		blit_op->dst.p0 = dst_p0;
 	}
 
 	if ((dst_h < 0) || (src_w < 0))
@@ -547,8 +555,9 @@
 			tmp_v =
 				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
 				MDP_MAX_X_SCALE_FACTOR +
-				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
-				MDP_MAX_X_SCALE_FACTOR ? 1 : 0;
+				((MDP_SCALE_Q_FACTOR *
+				blit_op->dst.roi.height) %
+				MDP_MAX_X_SCALE_FACTOR ? 1 : 0);
 
 			/* move x location as roi width gets bigger */
 			blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width;
@@ -558,8 +567,9 @@
 			tmp_v =
 				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
 				MDP_MIN_X_SCALE_FACTOR +
-				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
-				MDP_MIN_X_SCALE_FACTOR ? 1 : 0;
+				((MDP_SCALE_Q_FACTOR *
+				blit_op->dst.roi.height) %
+				MDP_MIN_X_SCALE_FACTOR ? 1 : 0);
 
 			/*
 			 * we don't move x location for continuity of
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
index e1c0f27..e562ad3 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_data.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -16,6 +16,8 @@
 #include "mdss_fb.h"
 #include "mdp3_ppp.h"
 
+#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+
 /* bg_config_lut not needed since it is same as src */
 const uint32_t src_cfg_lut[MDP_IMGTYPE_LIMIT] = {
 	[MDP_RGB_565] = MDP_RGB_565_SRC_REG,
@@ -34,6 +36,7 @@
 	[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG,
 	[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
 	[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+	[MDP_BGRX_8888] = MDP_RGBX_8888_SRC_REG,
 };
 
 const uint32_t out_cfg_lut[MDP_IMGTYPE_LIMIT] = {
@@ -53,6 +56,7 @@
 	[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG,
 	[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
 	[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+	[MDP_BGRX_8888] = MDP_RGBX_8888_DST_REG,
 };
 
 const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = {
@@ -60,8 +64,8 @@
 	[MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
 	[MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
 	[MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
-	[MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
-		CLR_G, CLR_B, 8),
+	[MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+		CLR_G, CLR_R, 8),
 	[MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
 		CLR_G, CLR_B, 8),
 	[MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
@@ -80,6 +84,8 @@
 		CLR_CR, CLR_Y, CLR_CB, 8),
 	[MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
 	[MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+	[MDP_BGRX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+		CLR_G, CLR_R, 8),
 };
 
 const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = {
@@ -119,6 +125,7 @@
 	[MDP_Y_CRCB_H2V1] = 1,
 	[MDP_Y_CRCB_H2V2] = 1,
 	[MDP_YCRYCB_H2V1] = 2,
+	[MDP_BGRX_8888] = 4,
 };
 
 const bool per_pixel_alpha[MDP_IMGTYPE_LIMIT] = {
@@ -1504,56 +1511,56 @@
 
 uint32_t ppp_bpp(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return bytes_per_pixel[type];
 }
 
 uint32_t ppp_src_config(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return src_cfg_lut[type];
 }
 
 uint32_t ppp_out_config(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return out_cfg_lut[type];
 }
 
 uint32_t ppp_pack_pattern(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return pack_patt_lut[type];
 }
 
 uint32_t ppp_dst_op_reg(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return dst_op_reg[type];
 }
 
 uint32_t ppp_src_op_reg(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return src_op_reg[type];
 }
 
 bool ppp_per_p_alpha(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return per_pixel_alpha[type];
 }
 
 bool ppp_multi_plane(uint32_t type)
 {
-	if (type > MDP_IMGTYPE_LIMIT)
+	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
 	return multi_plane[type];
 }
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index a051037..eb01d00 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -354,6 +354,7 @@
 	case MDP_ARGB_8888:
 	case MDP_XRGB_8888:
 	case MDP_RGBX_8888:
+	case MDP_BGRX_8888:
 		rgb = true;
 	default:
 		break;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index dd1a95b..5857606 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -68,6 +68,9 @@
 	u32 mdp_rev;
 	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;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e156116..c94db64 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -289,6 +289,7 @@
 {
 	int ret = 0;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_panel_info *panel_info = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -305,6 +306,7 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
+	panel_info = &ctrl_pdata->panel_data.panel_info;
 	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
 				ctrl_pdata, ctrl_pdata->ndx);
 
@@ -335,6 +337,11 @@
 		return ret;
 	}
 
+	if (panel_info->dynamic_fps
+	    && (panel_info->dfps_update == DFPS_SUSPEND_RESUME_MODE)
+	    && (panel_info->new_fps != panel_info->mipi.frame_rate))
+		panel_info->mipi.frame_rate = panel_info->new_fps;
+
 	pr_debug("%s-:\n", __func__);
 
 	return ret;
@@ -350,6 +357,7 @@
 	u32 ystride, bpp, data, dst_bpp;
 	u32 dummy_xres, dummy_yres;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 hsync_period, vsync_period;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -412,11 +420,16 @@
 			pdata->panel_info.bpp);
 	height = pdata->panel_info.yres;
 
-	mipi  = &pdata->panel_info.mipi;
 	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		dummy_xres = pdata->panel_info.lcdc.xres_pad;
 		dummy_yres = pdata->panel_info.lcdc.yres_pad;
+	}
 
+	vsync_period = vspw + vbp + height + dummy_yres + vfp;
+	hsync_period = hspw + hbp + width + dummy_xres + hfp;
+
+	mipi  = &pdata->panel_info.mipi;
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
 			((hspw + hbp + width + dummy_xres) << 16 |
 			(hspw + hbp)));
@@ -424,9 +437,8 @@
 			((vspw + vbp + height + dummy_yres) << 16 |
 			(vspw + vbp)));
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
-			(vspw + vbp + height + dummy_yres +
-				vfp - 1) << 16 | (hspw + hbp +
-				width + dummy_xres + hfp - 1));
+				((vsync_period - 1) << 16)
+				| (hsync_period - 1));
 
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16));
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0);
@@ -591,6 +603,102 @@
 	return ret;
 }
 
+static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
+{
+	int rc = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 dsi_ctrl;
+
+	pr_debug("%s+:\n", __func__);
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	if (!ctrl_pdata->panel_data.panel_info.dynamic_fps) {
+		pr_err("%s: Dynamic fps not enabled for this panel\n",
+					__func__);
+		return -EINVAL;
+	}
+
+	if (new_fps !=
+		ctrl_pdata->panel_data.panel_info.mipi.frame_rate) {
+		rc = mdss_dsi_clk_div_config
+			(&ctrl_pdata->panel_data.panel_info, new_fps);
+		if (rc) {
+			pr_err("%s: unable to initialize the clk dividers\n",
+							__func__);
+			return rc;
+		}
+		ctrl_pdata->pclk_rate =
+			ctrl_pdata->panel_data.panel_info.mipi.dsi_pclk_rate;
+		ctrl_pdata->byte_clk_rate =
+			ctrl_pdata->panel_data.panel_info.clk_rate / 8;
+
+		if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+			dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
+					    0x0004);
+			ctrl_pdata->panel_data.panel_info.mipi.frame_rate =
+									new_fps;
+			dsi_ctrl &= ~0x2;
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+							dsi_ctrl);
+			mdss_dsi_controller_cfg(true, pdata);
+			mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+			mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+			dsi_ctrl |= 0x2;
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+							dsi_ctrl);
+		}
+	} else {
+		pr_debug("%s: Panel is already at this FPS\n", __func__);
+	}
+
+	return rc;
+}
+
+static int mdss_dsi_ctl_partial_update(struct mdss_panel_data *pdata)
+{
+	int rc = -EINVAL;
+	u32 data;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	/* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
+	data = (((pdata->panel_info.roi_w * 3) + 1) << 16) |
+			(pdata->panel_info.mipi.vc << 8) | DTYPE_DCS_LWRITE;
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, data);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, data);
+
+	/* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
+	data = pdata->panel_info.roi_h << 16 | pdata->panel_info.roi_w;
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
+
+	if (ctrl_pdata->partial_update_fnc)
+		rc = ctrl_pdata->partial_update_fnc(pdata);
+
+	if (rc) {
+		pr_err("%s: unable to initialize the panel\n",
+				__func__);
+		return rc;
+	}
+
+	return rc;
+}
+
 static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
 				  int event, void *arg)
 {
@@ -643,7 +751,14 @@
 		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);
+	case MDSS_EVENT_PANEL_UPDATE_FPS:
+		if (arg != NULL) {
+			rc = mdss_dsi_dfps_config(pdata, (int)arg);
+			pr_debug("%s:update fps to = %d\n",
+				__func__, (int)arg);
+		}
 		break;
 	case MDSS_EVENT_CONT_SPLASH_BEGIN:
 		if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) {
@@ -651,6 +766,9 @@
 			rc = mdss_dsi_blank(pdata);
 		}
 		break;
+	case MDSS_EVENT_ENABLE_PARTIAL_UPDATE:
+		rc = mdss_dsi_ctl_partial_update(pdata);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
@@ -952,77 +1070,24 @@
 {
 	struct mipi_panel_info *mipi;
 	int rc, i, len;
-	u8 lanes = 0, bpp;
-	u32 h_period, v_period, dsi_pclk_rate, tmp[9];
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
+	bool dynamic_fps;
 	const char *data;
 	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((pinfo->lcdc.h_pulse_width)
-			+ (pinfo->lcdc.h_back_porch)
-			+ (pinfo->xres)
-			+ (pinfo->lcdc.h_front_porch));
-
-	v_period = ((pinfo->lcdc.v_pulse_width)
-			+ (pinfo->lcdc.v_back_porch)
-			+ (pinfo->yres)
-			+ (pinfo->lcdc.v_front_porch));
-
-	mipi  = &pinfo->mipi;
 	mipi  = &(pinfo->mipi);
 
 	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
-	if (mipi->data_lane3)
-		lanes += 1;
-	if (mipi->data_lane2)
-		lanes += 1;
-	if (mipi->data_lane1)
-		lanes += 1;
-	if (mipi->data_lane0)
-		lanes += 1;
-
-
-	if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
-	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
-	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
-		bpp = 3;
-	else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
-		 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
-		bpp = 2;
-	else
-		bpp = 3;		/* Default format set to RGB888 */
-
-	if (!pinfo->clk_rate) {
-		h_period += pinfo->lcdc.xres_pad;
-		v_period += pinfo->lcdc.yres_pad;
-
-		if (lanes > 0) {
-			pinfo->clk_rate =
-			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
-			   / lanes);
-		} else {
-			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			pinfo->clk_rate =
-				(h_period * v_period
-					 * (mipi->frame_rate) * bpp * 8);
-		}
-	}
-	pll_divider_config.clk_rate = pinfo->clk_rate;
-
-	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
+	rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate);
 	if (rc) {
 		pr_err("%s: unable to initialize the clk dividers\n", __func__);
 		return rc;
 	}
 
-	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
-		dsi_pclk_rate = 35000000;
-	mipi->dsi_pclk_rate = dsi_pclk_rate;
-
 	dsi_ctrl_np = of_parse_phandle(pan_node,
 				"qcom,mdss-dsi-panel-controller", 0);
 	if (!dsi_ctrl_np) {
@@ -1088,6 +1153,43 @@
 	ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool(
 		pan_node, "qcom,mdss-dsi-panel-broadcast-mode");
 
+	dynamic_fps = of_property_read_bool(pan_node,
+					  "qcom,mdss-dsi-pan-enable-dynamic-fps");
+	if (dynamic_fps) {
+		pinfo->dynamic_fps = true;
+		data = of_get_property(pan_node,
+					  "qcom,mdss-dsi-pan-fps-update", NULL);
+		if (data) {
+			if (!strcmp(data, "dfps_suspend_resume_mode")) {
+				pinfo->dfps_update =
+						DFPS_SUSPEND_RESUME_MODE;
+				pr_debug("%s: dfps mode: suspend/resume\n",
+								__func__);
+			} else if (!strcmp(data,
+					    "dfps_immediate_clk_mode")) {
+				pinfo->dfps_update =
+						DFPS_IMMEDIATE_CLK_UPDATE_MODE;
+				pr_debug("%s: dfps mode: Immediate clk\n",
+								__func__);
+			} else {
+				pr_debug("%s: dfps to default mode\n",
+								__func__);
+				pinfo->dfps_update =
+						DFPS_SUSPEND_RESUME_MODE;
+				pr_debug("%s: dfps mode: suspend/resume\n",
+								__func__);
+			}
+		} else {
+			pr_debug("%s: dfps update mode not configured\n",
+								__func__);
+				pinfo->dynamic_fps =
+								false;
+				pr_debug("%s: dynamic FPS disabled\n",
+								__func__);
+		}
+		pinfo->new_fps = pinfo->mipi.frame_rate;
+	}
+
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 		"qcom,platform-enable-gpio", 0);
 
@@ -1146,15 +1248,6 @@
 					ctrl_pdata->disp_te_gpio);
 	}
 
-	rc = of_property_read_u32_array(ctrl_pdev->dev.of_node,
-		"qcom,platform-reset-sequence", tmp, MDSS_DSI_RST_SEQ_LEN);
-	if (rc)
-		pr_err("%s:%d, unable to read gpio reset sequence\n",
-						__func__, __LINE__);
-	else
-		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i)
-			ctrl_pdata->rst_seq[i] = tmp[i];
-
 	ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 			 "qcom,platform-reset-gpio", 0);
 	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -1219,7 +1312,7 @@
 	 * register in mdp driver
 	 */
 
-	ctrl_pdata->pclk_rate = dsi_pclk_rate;
+	ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate;
 	ctrl_pdata->byte_clk_rate = pinfo->clk_rate / 8;
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 2d63532..6953d8b 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -194,8 +194,6 @@
 
 #define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
 
-#define MDSS_DSI_RST_SEQ_LEN 6
-
 struct dsi_buf {
 	u32 *hdr;	/* dsi host header */
 	char *start;	/* buffer start addr */
@@ -309,10 +307,15 @@
 	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);
 	int (*off) (struct mdss_panel_data *pdata);
+	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
 	int reg_size;
@@ -330,19 +333,25 @@
 	int disp_en_gpio;
 	int disp_te_gpio;
 	int mode_gpio;
+	int rst_gpio_requested;
+	int disp_en_gpio_requested;
+	int disp_te_gpio_requested;
+	int mode_gpio_requested;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_period;
 	int pwm_pmic_gpio;
 	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;
 	u32 byte_clk_rate;
 	struct dss_module_power power_data;
-	int rst_seq[MDSS_DSI_RST_SEQ_LEN];
 	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;
@@ -385,7 +394,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);
@@ -397,8 +406,8 @@
 void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
-int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
-			    u32 *expected_dsi_pclk);
+int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
+			    int frame_rate);
 int mdss_dsi_clk_init(struct platform_device *pdev,
 		      struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 62bc7e6..845ef10 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);
 }
@@ -1746,9 +1836,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 +1928,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 +1958,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 +2049,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 203900c..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,16 @@
 	pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	if (enable) {
-		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i) {
-			gpio_set_value((ctrl_pdata->rst_gpio),
-				ctrl_pdata->rst_seq[i]);
-			msleep(ctrl_pdata->rst_seq[++i]);
-		}
 		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->mode_gpio)) {
 			if (pinfo->mode_gpio_state == MODE_GPIO_HIGH)
 				gpio_set_value((ctrl_pdata->mode_gpio), 1);
@@ -209,6 +224,61 @@
 	}
 }
 
+static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00};	/* DTYPE_DCS_LWRITE */
+static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00};	/* DTYPE_DCS_LWRITE */
+
+static struct dsi_cmd_desc partial_update_enable_cmd[] = {
+	{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(caset)}, caset},
+	{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset},
+};
+
+static int mdss_dsi_panel_partial_update(struct mdss_panel_data *pdata)
+{
+	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
+	struct dcs_cmd_req cmdreq;
+	int rc = 0;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	mipi  = &pdata->panel_info.mipi;
+
+	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
+
+	caset[1] = (((pdata->panel_info.roi_x) & 0xFF00) >> 8);
+	caset[2] = (((pdata->panel_info.roi_x) & 0xFF));
+	caset[3] = (((pdata->panel_info.roi_x - 1 + pdata->panel_info.roi_w)
+								& 0xFF00) >> 8);
+	caset[4] = (((pdata->panel_info.roi_x - 1 + pdata->panel_info.roi_w)
+								& 0xFF));
+	partial_update_enable_cmd[0].payload = caset;
+
+	paset[1] = (((pdata->panel_info.roi_y) & 0xFF00) >> 8);
+	paset[2] = (((pdata->panel_info.roi_y) & 0xFF));
+	paset[3] = (((pdata->panel_info.roi_y - 1 + pdata->panel_info.roi_h)
+								& 0xFF00) >> 8);
+	paset[4] = (((pdata->panel_info.roi_y - 1 + pdata->panel_info.roi_h)
+								& 0xFF));
+	partial_update_enable_cmd[1].payload = paset;
+
+	pr_debug("%s: enabling partial update\n", __func__);
+	memset(&cmdreq, 0, sizeof(cmdreq));
+	cmdreq.cmds = partial_update_enable_cmd;
+	cmdreq.cmds_cnt = 2;
+	cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
+	cmdreq.rlen = 0;
+	cmdreq.cb = NULL;
+
+	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+
+	return rc;
+}
+
 static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
 							u32 bl_level)
 {
@@ -492,6 +562,35 @@
 }
 
 
+static int mdss_dsi_parse_reset_seq(struct device_node *np,
+		u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len,
+		const char *name)
+{
+	int num = 0, i;
+	int rc;
+	struct property *data;
+	u32 tmp[MDSS_DSI_RST_SEQ_LEN];
+	*rst_len = 0;
+	data = of_find_property(np, name, &num);
+	num /= sizeof(u32);
+	if (!data || !num || num > MDSS_DSI_RST_SEQ_LEN || num % 2) {
+		pr_debug("%s:%d, error reading %s, length found = %d\n",
+			__func__, __LINE__, name, num);
+	} else {
+		rc = of_property_read_u32_array(np, name, tmp, num);
+		if (rc)
+			pr_debug("%s:%d, error reading %s, rc = %d\n",
+				__func__, __LINE__, name, rc);
+		else {
+			for (i = 0; i < num; ++i)
+				rst_seq[i] = tmp[i];
+			*rst_len = num;
+		}
+	}
+	return 0;
+}
+
+
 static int mdss_panel_parse_dt(struct device_node *np,
 			struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
@@ -740,6 +839,9 @@
 
 	mdss_dsi_parse_fbc_params(np, pinfo);
 
+	mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
+		"qcom,mdss-dsi-reset-sequence");
+
 	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->on_cmds,
 		"qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
 
@@ -759,6 +861,7 @@
 	int rc = 0;
 	static const char *panel_name;
 	bool cont_splash_enabled;
+	bool partial_update_enabled;
 
 	if (!node) {
 		pr_err("%s: no panel node\n", __func__);
@@ -795,6 +898,18 @@
 		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
 	}
 
+	partial_update_enabled = of_property_read_bool(node,
+						"qcom,partial-update-enabled");
+	if (partial_update_enabled) {
+		pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
+		ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
+		ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
+	} else {
+		pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
+		ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
+		ctrl_pdata->partial_update_fnc = NULL;
+	}
+
 	ctrl_pdata->on = mdss_dsi_panel_on;
 	ctrl_pdata->off = mdss_dsi_panel_off;
 	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 9c0daa9..4ca0a3f 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -242,12 +242,28 @@
 	return ret;
 }
 
+static ssize_t mdss_mdp_show_blank_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	int ret;
+
+	pr_debug("fb%d panel_power_on = %d\n", mfd->index, mfd->panel_power_on);
+	ret = scnprintf(buf, PAGE_SIZE, "panel_power_on = %d\n",
+						mfd->panel_power_on);
+
+	return ret;
+}
+
 static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
+static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
 
 static struct attribute *mdss_fb_attrs[] = {
 	&dev_attr_msm_fb_type.attr,
 	&dev_attr_msm_fb_split.attr,
+	&dev_attr_show_blank_event.attr,
 	NULL,
 };
 
@@ -360,18 +376,24 @@
 	mdss_fb_create_sysfs(mfd);
 	mdss_fb_send_panel_event(mfd, MDSS_EVENT_FB_REGISTERED, fbi);
 
-	if (mfd->timeline == NULL) {
+	mfd->mdp_sync_pt_data.fence_name = "mdp-fence";
+	if (mfd->mdp_sync_pt_data.timeline == NULL) {
 		char timeline_name[16];
 		snprintf(timeline_name, sizeof(timeline_name),
 			"mdss_fb_%d", mfd->index);
-		mfd->timeline = sw_sync_timeline_create(timeline_name);
-		if (mfd->timeline == NULL) {
+		 mfd->mdp_sync_pt_data.timeline =
+				sw_sync_timeline_create(timeline_name);
+		if (mfd->mdp_sync_pt_data.timeline == NULL) {
 			pr_err("%s: cannot create time line", __func__);
 			return -ENOMEM;
 		} else {
-			mfd->timeline_value = 0;
+			mfd->mdp_sync_pt_data.timeline_value = 0;
 		}
 	}
+	if (mfd->panel.type == WRITEBACK_PANEL)
+		mfd->mdp_sync_pt_data.threshold = 1;
+	else
+		mfd->mdp_sync_pt_data.threshold = 2;
 
 	return rc;
 }
@@ -569,9 +591,6 @@
 	},
 };
 
-static int unset_bl_level, bl_updated;
-static int bl_level_old;
-
 static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
 {
 	u32 temp = *bl_lvl;
@@ -593,11 +612,11 @@
 		 * scaling fraction (x/1024)
 		 */
 		temp = (temp * mfd->bl_scale) / 1024;
-
-		/*if less than minimum level, use min level*/
-		if (temp < mfd->bl_min_lvl)
-			temp = mfd->bl_min_lvl;
 	}
+	/*if less than minimum level, use min level*/
+	else if ((temp < mfd->bl_min_lvl) && (0 != temp))
+		temp = mfd->bl_min_lvl;
+
 	pr_debug("output = %d", temp);
 
 	(*bl_lvl) = temp;
@@ -607,13 +626,18 @@
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
 {
 	struct mdss_panel_data *pdata;
+	int (*update_ad_input)(struct msm_fb_data_type *mfd);
 	u32 temp = bkl_lvl;
 
-	if ((!mfd->panel_power_on || !bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
-		unset_bl_level = bkl_lvl;
-		return;
+	if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
+		|| !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
+			if (bkl_lvl < mfd->bl_min_lvl)
+				mfd->unset_bl_level = mfd->bl_min_lvl;
+			else
+				mfd->unset_bl_level = bkl_lvl;
+			return;
 	} else {
-		unset_bl_level = 0;
+		mfd->unset_bl_level = 0;
 	}
 
 	pdata = dev_get_platdata(&mfd->pdev->dev);
@@ -629,18 +653,19 @@
 		 * as well as setting bl_level to bkl_lvl even though the
 		 * backlight has been set to the scaled value.
 		 */
-		if (bl_level_old == temp) {
+		if (mfd->bl_level_old == temp) {
 			mfd->bl_level = bkl_lvl;
 			return;
 		}
 		pdata->set_backlight(pdata, temp);
 		mfd->bl_level = bkl_lvl;
-		bl_level_old = temp;
+		mfd->bl_level_old = temp;
 
 		if (mfd->mdp.update_ad_input) {
+			update_ad_input = mfd->mdp.update_ad_input;
 			mutex_unlock(&mfd->bl_lock);
 			/* Will trigger ad_setup which will grab bl_lock */
-			mfd->mdp.update_ad_input(mfd);
+			update_ad_input(mfd);
 			mutex_lock(&mfd->bl_lock);
 		}
 	}
@@ -650,15 +675,15 @@
 {
 	struct mdss_panel_data *pdata;
 
-	if (unset_bl_level && !bl_updated) {
+	if (mfd->unset_bl_level && !mfd->bl_updated) {
 		pdata = dev_get_platdata(&mfd->pdev->dev);
 		if ((pdata) && (pdata->set_backlight)) {
 			mutex_lock(&mfd->bl_lock);
-			mfd->bl_level = unset_bl_level;
+			mfd->bl_level = mfd->unset_bl_level;
 			pdata->set_backlight(pdata, mfd->bl_level);
-			bl_level_old = unset_bl_level;
+			mfd->bl_level_old = mfd->unset_bl_level;
 			mutex_unlock(&mfd->bl_lock);
-			bl_updated = 1;
+			mfd->bl_updated = 1;
 		}
 	}
 }
@@ -705,7 +730,7 @@
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
 			mfd->panel_power_on = false;
-			bl_updated = 0;
+			mfd->bl_updated = 0;
 
 			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
@@ -1060,7 +1085,8 @@
 
 	mutex_init(&mfd->update.lock);
 	mutex_init(&mfd->no_update.lock);
-	mutex_init(&mfd->sync_mutex);
+	mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);
+
 	init_timer(&mfd->no_update.timer);
 	mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
 	mfd->no_update.timer.data = (unsigned long)mfd;
@@ -1165,6 +1191,12 @@
 	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);
@@ -1215,18 +1247,18 @@
 	}
 }
 
-void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd)
+void mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
 {
 	int i, ret = 0;
 	/* buf sync */
-	for (i = 0; i < mfd->acq_fen_cnt; i++) {
-		ret = sync_fence_wait(mfd->acq_fen[i],
+	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++) {
+		ret = sync_fence_wait(sync_pt_data->acq_fen[i],
 				WAIT_FENCE_FIRST_TIMEOUT);
 		if (ret == -ETIME) {
 			pr_warn("sync_fence_wait timed out! ");
 			pr_cont("Waiting %ld more seconds\n",
 					WAIT_FENCE_FINAL_TIMEOUT/MSEC_PER_SEC);
-			ret = sync_fence_wait(mfd->acq_fen[i],
+			ret = sync_fence_wait(sync_pt_data->acq_fen[i],
 					WAIT_FENCE_FINAL_TIMEOUT);
 		}
 		if (ret < 0) {
@@ -1234,46 +1266,46 @@
 				__func__, ret);
 			break;
 		}
-		sync_fence_put(mfd->acq_fen[i]);
+		sync_fence_put(sync_pt_data->acq_fen[i]);
 	}
 
 	if (ret < 0) {
-		while (i < mfd->acq_fen_cnt) {
-			sync_fence_put(mfd->acq_fen[i]);
+		while (i < sync_pt_data->acq_fen_cnt) {
+			sync_fence_put(sync_pt_data->acq_fen[i]);
 			i++;
 		}
 	}
-	mfd->acq_fen_cnt = 0;
+	sync_pt_data->acq_fen_cnt = 0;
 }
 
-static void mdss_fb_signal_timeline_locked(struct msm_fb_data_type *mfd)
+static void mdss_fb_signal_timeline_locked(
+				struct msm_sync_pt_data *sync_pt_data)
 {
-	if (mfd->timeline && !list_empty((const struct list_head *)
-				(&(mfd->timeline->obj.active_list_head)))) {
-		sw_sync_timeline_inc(mfd->timeline, 1);
-		mfd->timeline_value++;
+	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++;
 	}
-	mfd->last_rel_fence = mfd->cur_rel_fence;
-	mfd->cur_rel_fence = 0;
+	sync_pt_data->cur_rel_fence = 0;
 }
 
-void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd)
+void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data)
 {
-	mutex_lock(&mfd->sync_mutex);
-	mdss_fb_signal_timeline_locked(mfd);
-	mutex_unlock(&mfd->sync_mutex);
+	mutex_lock(&sync_pt_data->sync_mutex);
+	mdss_fb_signal_timeline_locked(sync_pt_data);
+	mutex_unlock(&sync_pt_data->sync_mutex);
 }
 
 static void mdss_fb_release_fences(struct msm_fb_data_type *mfd)
 {
-	mutex_lock(&mfd->sync_mutex);
-	if (mfd->timeline) {
-		sw_sync_timeline_inc(mfd->timeline, 2);
-		mfd->timeline_value += 2;
+
+	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;
 	}
-	mfd->last_rel_fence = 0;
-	mfd->cur_rel_fence = 0;
-	mutex_unlock(&mfd->sync_mutex);
+	mfd->mdp_sync_pt_data.cur_rel_fence = 0;
+	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 }
 
 static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
@@ -1290,11 +1322,11 @@
 			pr_err("%s wait for commit_comp timeout %d %d",
 				__func__, ret, mfd->is_committing);
 		if (ret <= 0) {
-			mutex_lock(&mfd->sync_mutex);
-			mdss_fb_signal_timeline_locked(mfd);
+			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->sync_mutex);
+			mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 		}
 	}
 }
@@ -1319,7 +1351,7 @@
 
 	mdss_fb_pan_idle(mfd);
 
-	mutex_lock(&mfd->sync_mutex);
+	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (info->fix.xpanstep)
 		info->var.xoffset =
 		(var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
@@ -1335,7 +1367,7 @@
 	INIT_COMPLETION(mfd->commit_comp);
 	mfd->is_committing = 1;
 	schedule_work(&mfd->commit_work);
-	mutex_unlock(&mfd->sync_mutex);
+	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (wait_for_finish)
 		mdss_fb_pan_idle(mfd);
 	return ret;
@@ -1373,13 +1405,13 @@
 		info->var.yoffset =
 		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
 
-	mdss_fb_wait_for_fence(mfd);
+	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);
+	mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
 	mdss_fb_update_backlight(mfd);
 	return 0;
 }
@@ -1404,28 +1436,29 @@
 	struct fb_var_screeninfo *var;
 	struct fb_info *info;
 	struct msm_fb_backup_type *fb_backup;
-	int ret;
+	int ret = 0;
 
 	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);
+		mdss_fb_wait_for_fence(&mfd->mdp_sync_pt_data);
 		if (mfd->mdp.kickoff_fnc)
-			mfd->mdp.kickoff_fnc(mfd);
-		mdss_fb_update_backlight(mfd);
-		mdss_fb_signal_timeline(mfd);
+			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);
 	} else {
 		var = &fb_backup->disp_commit.var;
 		ret = mdss_fb_pan_display_sub(var, info);
 		if (ret)
 			pr_err("%s fails: ret = %x", __func__, ret);
 	}
-	mutex_lock(&mfd->sync_mutex);
+	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
 	mfd->is_committing = 0;
 	complete_all(&mfd->commit_comp);
-	mutex_unlock(&mfd->sync_mutex);
+	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 }
 
 static int mdss_fb_check_var(struct fb_var_screeninfo *var,
@@ -1683,21 +1716,17 @@
 	return 0;
 }
 
-static int mdss_fb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
-						struct mdp_buf_sync *buf_sync)
+static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
+				 struct mdp_buf_sync *buf_sync)
 {
-	int i, fence_cnt = 0, ret = 0;
+	int i, ret = 0;
 	int acq_fen_fd[MDP_MAX_FENCE_FD];
 	struct sync_fence *fence;
-	u32 threshold;
 
 	if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
-		(mfd->timeline == NULL))
+				(sync_pt_data->timeline == NULL))
 		return -EINVAL;
 
-	if ((!mfd->op_enable) || (!mfd->panel_power_on))
-		return -EPERM;
-
 	if (buf_sync->acq_fen_fd_cnt)
 		ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
 				buf_sync->acq_fen_fd_cnt * sizeof(int));
@@ -1705,7 +1734,8 @@
 		pr_err("%s:copy_from_user failed", __func__);
 		return ret;
 	}
-	mutex_lock(&mfd->sync_mutex);
+
+	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) {
@@ -1714,64 +1744,65 @@
 			ret = -EINVAL;
 			break;
 		}
-		mfd->acq_fen[i] = fence;
+		sync_pt_data->acq_fen[i] = fence;
 	}
-	fence_cnt = i;
+	sync_pt_data->acq_fen_cnt = i;
 	if (ret)
 		goto buf_sync_err_1;
-	mfd->acq_fen_cnt = fence_cnt;
+
 	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
-		mdss_fb_wait_for_fence(mfd);
+		mdss_fb_wait_for_fence(sync_pt_data);
 
-	if (mfd->panel.type == WRITEBACK_PANEL)
-		threshold = 1;
-	else
-		threshold = 2;
+	sync_pt_data->cur_rel_sync_pt = sw_sync_pt_create(
+			sync_pt_data->timeline, sync_pt_data->timeline_value +
+					sync_pt_data->threshold);
 
-	mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
-			mfd->timeline_value + threshold);
-	if (mfd->cur_rel_sync_pt == NULL) {
+	if (sync_pt_data->cur_rel_sync_pt == NULL) {
 		pr_err("%s: cannot create sync point", __func__);
 		ret = -ENOMEM;
 		goto buf_sync_err_1;
 	}
 	/* create fence */
-	mfd->cur_rel_fence = sync_fence_create("mdp-fence",
-			mfd->cur_rel_sync_pt);
-	if (mfd->cur_rel_fence == NULL) {
-		sync_pt_free(mfd->cur_rel_sync_pt);
-		mfd->cur_rel_sync_pt = NULL;
+	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 */
-	mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
-	if (mfd->cur_rel_fen_fd < 0) {
+	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;
 		goto buf_sync_err_2;
 	}
-	sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
+
+	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,
-		&mfd->cur_rel_fen_fd, sizeof(int));
+				&sync_pt_data->cur_rel_fen_fd, sizeof(int));
+
 	if (ret) {
 		pr_err("%s:copy_to_user failed", __func__);
 		goto buf_sync_err_3;
 	}
-	mutex_unlock(&mfd->sync_mutex);
+	mutex_unlock(&sync_pt_data->sync_mutex);
 	return ret;
 buf_sync_err_3:
-	put_unused_fd(mfd->cur_rel_fen_fd);
+	put_unused_fd(sync_pt_data->cur_rel_fen_fd);
 buf_sync_err_2:
-	sync_fence_put(mfd->cur_rel_fence);
-	mfd->cur_rel_fence = NULL;
-	mfd->cur_rel_fen_fd = 0;
+	sync_fence_put(sync_pt_data->cur_rel_fence);
+	sync_pt_data->cur_rel_fence = NULL;
+	sync_pt_data->cur_rel_fen_fd = 0;
 buf_sync_err_1:
-	for (i = 0; i < fence_cnt; i++)
-		sync_fence_put(mfd->acq_fen[i]);
-	mfd->acq_fen_cnt = 0;
-	mutex_unlock(&mfd->sync_mutex);
+	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
+		sync_fence_put(sync_pt_data->acq_fen[i]);
+	sync_pt_data->acq_fen_cnt = 0;
+	mutex_unlock(&sync_pt_data->sync_mutex);
 	return ret;
 }
 static int mdss_fb_display_commit(struct fb_info *info,
@@ -1798,7 +1829,7 @@
 	struct mdp_page_protection fb_page_protection;
 	int ret = -ENOSYS;
 	struct mdp_buf_sync buf_sync;
-
+	struct msm_sync_pt_data *sync_pt_data = NULL;
 	if (!info || !info->par)
 		return -EINVAL;
 	mfd = (struct msm_fb_data_type *)info->par;
@@ -1828,8 +1859,14 @@
 		ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
 		if (ret)
 			return ret;
+		if ((!mfd->op_enable) || (!mfd->panel_power_on))
+			return -EPERM;
+		if (mfd->mdp.get_sync_fnc)
+			sync_pt_data = mfd->mdp.get_sync_fnc(mfd, &buf_sync);
+		if (!sync_pt_data)
+			sync_pt_data = &mfd->mdp_sync_pt_data;
 
-		ret = mdss_fb_handle_buf_sync_ioctl(mfd, &buf_sync);
+		ret = mdss_fb_handle_buf_sync_ioctl(sync_pt_data, &buf_sync);
 
 		if (!ret)
 			ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync));
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index fd96e63..256789d 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -53,6 +53,19 @@
 	int value;
 };
 
+struct msm_sync_pt_data {
+	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;
+	struct mutex sync_mutex;
+};
+
 struct msm_fb_data_type;
 
 struct msm_mdp_interface {
@@ -63,7 +76,8 @@
 	int (*off_fnc)(struct msm_fb_data_type *mfd);
 	/* called to release resources associated to the process */
 	int (*release_fnc)(struct msm_fb_data_type *mfd);
-	int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
+	int (*kickoff_fnc)(struct msm_fb_data_type *mfd,
+					struct mdp_display_commit *data);
 	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 	void (*dma_fnc)(struct msm_fb_data_type *mfd);
 	int (*cursor_update)(struct msm_fb_data_type *mfd,
@@ -74,6 +88,8 @@
 	int (*update_ad_input)(struct msm_fb_data_type *mfd);
 	int (*panel_register_done)(struct mdss_panel_data *pdata);
 	u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+	struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
+				const struct mdp_buf_sync *buf_sync);
 	void *private1;
 };
 
@@ -124,6 +140,9 @@
 	u32 bl_level;
 	u32 bl_scale;
 	u32 bl_min_lvl;
+	u32 unset_bl_level;
+	u32 bl_updated;
+	u32 bl_level_old;
 	struct mutex bl_lock;
 	struct mutex lock;
 
@@ -137,17 +156,8 @@
 
 	struct msm_mdp_interface mdp;
 
-	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 sync_fence *last_rel_fence;
-	struct sw_sync_timeline *timeline;
-	int timeline_value;
-	u32 last_acq_fen_cnt;
-	struct sync_fence *last_acq_fen[MDP_MAX_FENCE_FD];
-	struct mutex sync_mutex;
+	struct msm_sync_pt_data mdp_sync_pt_data;
+
 	/* for non-blocking */
 	struct completion commit_comp;
 	u32 is_committing;
@@ -187,8 +197,8 @@
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
-void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd);
-void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd);
+void mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
+void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data);
 int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
 int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index b74f074..410f2b3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -350,7 +350,8 @@
 			(msg->operand[i] << 8) | frame_type);
 
 	while ((DSS_REG_R(io, HDMI_CEC_STATUS) & BIT(0)) &&
-		line_check_retry--) {
+		line_check_retry) {
+		line_check_retry--;
 		DEV_DBG("%s: CEC line is busy(%d)\n", __func__,
 			line_check_retry);
 		schedule();
@@ -756,7 +757,7 @@
 	hdmi_wta_cec_enable);
 static DEVICE_ATTR(enable_compliance, S_IRUGO | S_IWUSR,
 	hdmi_rda_cec_enable_compliance, hdmi_wta_cec_enable_compliance);
-static DEVICE_ATTR(logical_addr, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(logical_addr, S_IRUSR | S_IWUSR,
 	hdmi_rda_cec_logical_addr, hdmi_wta_cec_logical_addr);
 static DEVICE_ATTR(rd_msg, S_IRUGO, hdmi_rda_cec_msg,	NULL);
 static DEVICE_ATTR(wr_msg, S_IWUSR, NULL, hdmi_wta_cec_msg);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 65dc19c..0074873 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -27,6 +27,11 @@
 #define MAX_AUDIO_DATA_BLOCK_SIZE	30
 #define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE	3
 
+#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];
@@ -50,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;
@@ -249,19 +255,19 @@
 			if (!hdmi_get_supported_mode(*video_mode))
 				continue;
 			if (ret > 0)
-				ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
-					*video_mode++);
+				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+					",%d", *video_mode++);
 			else
-				ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
-					*video_mode++);
+				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+					"%d", *video_mode++);
 		}
 	} else {
-		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d",
 			edid_ctrl->video_resolution);
 	}
 
 	DEV_DBG("%s: '%s'\n", __func__, buf);
-	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
 
 	return ret;
 } /* hdmi_edid_sysfs_rda_modes */
@@ -279,12 +285,12 @@
 		return -EINVAL;
 	}
 
-	ret = snprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
+	ret = scnprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
 	DEV_DBG("%s: '%d'\n", __func__, edid_ctrl->physical_address);
 
 	return ret;
 } /* hdmi_edid_sysfs_rda_physical_address */
-static DEVICE_ATTR(pa, S_IRUGO, hdmi_edid_sysfs_rda_physical_address, NULL);
+static DEVICE_ATTR(pa, S_IRUSR, hdmi_edid_sysfs_rda_physical_address, NULL);
 
 static ssize_t hdmi_edid_sysfs_rda_scan_info(struct device *dev,
 	struct device_attribute *attr, char *buf)
@@ -298,7 +304,7 @@
 		return -EINVAL;
 	}
 
-	ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
+	ret = scnprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
 		edid_ctrl->it_scan_info, edid_ctrl->ce_scan_info);
 	DEV_DBG("%s: '%s'\n", __func__, buf);
 
@@ -311,7 +317,8 @@
 {
 	ssize_t ret = 0;
 	int i;
-	char buff_3d[128];
+	char buff_3d[BUFF_SIZE_3D];
+
 	struct hdmi_edid_ctrl *edid_ctrl =
 		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
 
@@ -327,33 +334,52 @@
 
 		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
 			ret = hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
-				buff_3d);
+				buff_3d, sizeof(buff_3d));
 			if (ret > 0)
-				ret += snprintf(buf+ret, PAGE_SIZE-ret,
+				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
 					",%d=%s", *video_mode++,
 					buff_3d);
 			else
-				ret += snprintf(buf+ret, PAGE_SIZE-ret,
+				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
 					"%d=%s", *video_mode++,
 					buff_3d);
 		}
 	} else {
-		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d",
 			edid_ctrl->video_resolution);
 	}
 
 	DEV_DBG("%s: '%s'\n", __func__, buf);
-	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
 
 	return ret;
 } /* 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,
 };
 
@@ -816,7 +842,7 @@
 static void hdmi_edid_add_sink_3d_format(struct hdmi_edid_sink_data *sink_data,
 	u32 video_format, u32 video_3d_format)
 {
-	char string[128];
+	char string[BUFF_SIZE_3D];
 	u32 added = false;
 	int i;
 
@@ -828,7 +854,7 @@
 		}
 	}
 
-	hdmi_get_video_3d_fmt_2string(video_3d_format, string);
+	hdmi_get_video_3d_fmt_2string(video_3d_format, string, sizeof(string));
 
 	DEV_DBG("%s: EDID[3D]: format: %d [%s], %s %s\n", __func__,
 		video_format, msm_hdmi_mode_2string(video_format),
@@ -1302,7 +1328,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;
@@ -1316,12 +1342,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,
@@ -1388,7 +1416,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);
@@ -1396,7 +1424,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..bf28e8c 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)
@@ -1192,10 +1285,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 0fd3655..0b64bbb 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -126,7 +126,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 +199,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;
@@ -327,7 +382,7 @@
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
 
-	if (!device || feature_type > HDMI_TX_FEAT_MAX) {
+	if (!device || feature_type >= HDMI_TX_FEAT_MAX) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return NULL;
 	}
@@ -544,6 +599,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 +659,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 = {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 53dfc71..711ec68 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -123,30 +123,30 @@
 	return "";
 } /* hdmi_get_single_video_3d_fmt_2string */
 
-ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf)
+ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size)
 {
 	ssize_t ret, len = 0;
-	ret = snprintf(buf, PAGE_SIZE, "%s",
+	ret = scnprintf(buf, size, "%s",
 		hdmi_get_single_video_3d_fmt_2string(
 			format & FRAME_PACKING));
 	len += ret;
 
 	if (len && (format & TOP_AND_BOTTOM))
-		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+		ret = scnprintf(buf + len, size - len, ":%s",
 			hdmi_get_single_video_3d_fmt_2string(
 				format & TOP_AND_BOTTOM));
 	else
-		ret = snprintf(buf + len, PAGE_SIZE, "%s",
+		ret = scnprintf(buf + len, size - len, "%s",
 			hdmi_get_single_video_3d_fmt_2string(
 				format & TOP_AND_BOTTOM));
 	len += ret;
 
 	if (len && (format & SIDE_BY_SIDE_HALF))
-		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+		ret = scnprintf(buf + len, size - len, ":%s",
 			hdmi_get_single_video_3d_fmt_2string(
 				format & SIDE_BY_SIDE_HALF));
 	else
-		ret = snprintf(buf + len, PAGE_SIZE, "%s",
+		ret = scnprintf(buf + len, size - len, "%s",
 			hdmi_get_single_video_3d_fmt_2string(
 				format & SIDE_BY_SIDE_HALF));
 	len += ret;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index e99e549..5f7878b 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -256,7 +256,7 @@
 int hdmi_get_video_id_code(struct msm_hdmi_mode_timing_info *timing_in);
 const struct msm_hdmi_mode_timing_info *hdmi_get_supported_mode(u32 mode);
 void hdmi_del_supported_mode(u32 mode);
-ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
+ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size);
 
 /* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
 void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 3107e38..db8a098 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -48,6 +48,7 @@
 #include <mach/iommu_domains.h>
 #include <mach/memory.h>
 #include <mach/msm_memtypes.h>
+#include <mach/rpm-regulator-smd.h>
 
 #include "mdss.h"
 #include "mdss_fb.h"
@@ -700,6 +701,14 @@
 	}
 	mdata->fs_ena = false;
 
+	mdata->vdd_cx = devm_regulator_get(&mdata->pdev->dev,
+				"vdd-cx");
+	if (IS_ERR_OR_NULL(mdata->vdd_cx)) {
+		pr_debug("unable to get CX reg. rc=%d\n",
+					PTR_RET(mdata->vdd_cx));
+		mdata->vdd_cx = NULL;
+	}
+
 	if (mdss_mdp_irq_clk_register(mdata, "bus_clk", MDSS_CLK_AXI) ||
 	    mdss_mdp_irq_clk_register(mdata, "iface_clk", MDSS_CLK_AHB) ||
 	    mdss_mdp_irq_clk_register(mdata, "core_clk_src",
@@ -1792,6 +1801,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);
@@ -1803,6 +1813,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;
 }
 
@@ -1931,6 +1944,76 @@
 	return rc;
 }
 
+static int mdss_mdp_cx_ctrl(struct mdss_data_type *mdata, int enable)
+{
+	int rc = 0;
+
+	if (!mdata->vdd_cx)
+		return rc;
+
+	if (enable) {
+		rc = regulator_set_voltage(
+				mdata->vdd_cx,
+				RPM_REGULATOR_CORNER_SVS_SOC,
+				RPM_REGULATOR_CORNER_SUPER_TURBO);
+		if (rc < 0)
+			goto vreg_set_voltage_fail;
+
+		pr_debug("Enabling CX power rail\n");
+		rc = regulator_enable(mdata->vdd_cx);
+		if (rc) {
+			pr_err("Failed to enable regulator.\n");
+			return rc;
+		}
+	} else {
+		pr_debug("Disabling CX power rail\n");
+		rc = regulator_disable(mdata->vdd_cx);
+		if (rc) {
+			pr_err("Failed to disable regulator.\n");
+			return rc;
+		}
+		rc = regulator_set_voltage(
+				mdata->vdd_cx,
+				RPM_REGULATOR_CORNER_NONE,
+				RPM_REGULATOR_CORNER_SUPER_TURBO);
+		if (rc < 0)
+			goto vreg_set_voltage_fail;
+	}
+
+	return rc;
+
+vreg_set_voltage_fail:
+	pr_err("Set vltg fail\n");
+	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)
@@ -1938,14 +2021,20 @@
 
 	if (on) {
 		pr_debug("Enable MDP FS\n");
-		if (!mdata->fs_ena)
+		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 {
 		pr_debug("Disable MDP FS\n");
 		mdss_iommu_dettach(mdata);
-		if (mdata->fs_ena)
+		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 351d52b..7bf14e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -114,6 +114,13 @@
 struct mdss_mdp_ctl;
 typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
 
+struct mdss_mdp_img_rect {
+	u16 x;
+	u16 y;
+	u16 w;
+	u16 h;
+};
+
 struct mdss_mdp_vsync_handler {
 	bool enabled;
 	bool cmd_post_flush;
@@ -153,6 +160,7 @@
 	u32 bus_ib_quota;
 	u32 clk_rate;
 	u32 perf_changed;
+	int force_screen_state;
 
 	struct mdss_data_type *mdata;
 	struct msm_fb_data_type *mfd;
@@ -164,6 +172,9 @@
 	struct mdss_panel_data *panel_data;
 	struct mdss_mdp_vsync_handler vsync_handler;
 
+	struct mdss_mdp_img_rect roi;
+	u8 roi_changed;
+
 	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
@@ -175,7 +186,7 @@
 					struct mdss_mdp_vsync_handler *);
 	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);
 	void *priv_data;
 	u32 wb_type;
 };
@@ -190,6 +201,7 @@
 	u8 params_changed;
 	u16 width;
 	u16 height;
+	struct mdss_mdp_img_rect roi;
 	u8 cursor_enabled;
 	u8 rotator_mode;
 
@@ -197,13 +209,6 @@
 	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
 };
 
-struct mdss_mdp_img_rect {
-	u16 x;
-	u16 y;
-	u16 w;
-	u16 h;
-};
-
 struct mdss_mdp_format_params {
 	u32 format;
 	u8 is_yuv;
@@ -387,6 +392,10 @@
 	struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE];
 	int free_list_size;
 	int ad_state;
+
+	u32 splash_mem_addr;
+	u32 splash_mem_size;
+	u32 sd_enabled;
 };
 
 struct mdss_mdp_perf_params {
@@ -395,6 +404,17 @@
 	u32 mdp_clk_rate;
 };
 
+/**
+ * enum mdss_screen_state - Screen states that MDP can be forced into
+ *
+ * @MDSS_SCREEN_DEFAULT:	Do not force MDP into any screen state.
+ * @MDSS_SCREEN_FORCE_BLANK:	Force MDP to generate blank color fill screen.
+ */
+enum mdss_screen_state {
+	MDSS_SCREEN_DEFAULT,
+	MDSS_SCREEN_FORCE_BLANK,
+};
+
 #define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
@@ -420,7 +440,6 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
 void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
 		u32 intr_type, u32 intf_num);
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -432,6 +451,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);
@@ -446,14 +466,13 @@
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
+		struct mdp_display_commit *data);
 
 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_video_copy_splash_screen(struct mdss_panel_data *pdata);
-void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
@@ -496,33 +515,18 @@
 
 int mdss_hw_init(struct mdss_data_type *mdata);
 
-int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_pa_cfg_data *config,
-				u32 *copyback);
-int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_pcc_cfg_data *cfg_ptr,
-				u32 *copyback);
-int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_igc_lut_data *config,
-				u32 *copyback, u32 copy_from_kernel);
-int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_pgc_lut_data *config,
-				u32 *copyback);
-int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_hist_lut_data *config,
-				u32 *copyback);
-int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_dither_cfg_data *config,
-				u32 *copyback);
-int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_gamut_cfg_data *config,
-				u32 *copyback);
+int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback,
+				u32 copy_from_kernel);
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
 
-int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block);
-int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_data *hist);
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_collect(struct mdp_histogram_data *hist);
 void mdss_mdp_hist_intr_done(u32 isr);
 
 int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
@@ -571,6 +575,9 @@
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_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,
+	const struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect);
 
 int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
@@ -583,11 +590,13 @@
 int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
 int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
 						u32 *copyback);
-
+int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps);
 int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
 struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
 					       u32 return_type);
+void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl,
+					struct mdp_display_commit *data);
 
 int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, int dst_format);
 int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
@@ -601,4 +610,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 7b36f2c..e50598f 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"
@@ -212,7 +214,14 @@
 
 	quota = fps * pipe->src.w * src_h;
 	if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
-		quota = (quota * 3) / 2;
+		/*
+		 * with decimation, chroma is not downsampled, this means we
+		 * need to allocate bw for extra lines that will be fetched
+		 */
+		if (pipe->vert_deci)
+			quota *= 2;
+		else
+			quota = (quota * 3) / 2;
 	else
 		quota *= pipe->src_fmt->bpp;
 
@@ -421,6 +430,7 @@
 	ctl->add_vsync_handler = NULL;
 	ctl->remove_vsync_handler = NULL;
 	ctl->panel_data = NULL;
+	ctl->config_fps_fnc = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
@@ -580,6 +590,11 @@
 {
 	struct mdss_mdp_ctl *ctl;
 
+	if (!mixer || !mixer->ctl) {
+		pr_err("invalid ctl handle\n");
+		return -ENODEV;
+	}
+
 	ctl = mixer->ctl;
 	mixer->rotator_mode = 0;
 
@@ -595,18 +610,6 @@
 	return 0;
 }
 
-void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
-{
-	switch (pdata->panel_info.type) {
-	case MIPI_VIDEO_PANEL:
-		mdss_mdp_video_copy_splash_screen(pdata);
-		break;
-	case MIPI_CMD_PANEL:
-	default:
-		break;
-	}
-}
-
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
 {
 	switch (ctl->panel_data->panel_info.type) {
@@ -720,6 +723,7 @@
 
 	ctl->width = width;
 	ctl->height = height;
+	ctl->roi = (struct mdss_mdp_img_rect) {0, 0, width, height};
 
 	if (!ctl->mixer_left) {
 		ctl->mixer_left =
@@ -738,6 +742,7 @@
 
 	ctl->mixer_left->width = width;
 	ctl->mixer_left->height = height;
+	ctl->mixer_left->roi = (struct mdss_mdp_img_rect) {0, 0, width, height};
 
 	if (split_ctl) {
 		pr_debug("split display detected\n");
@@ -760,6 +765,8 @@
 		}
 		ctl->mixer_right->width = width;
 		ctl->mixer_right->height = height;
+		ctl->mixer_right->roi = (struct mdss_mdp_img_rect)
+						{0, 0, width, height};
 	} else if (ctl->mixer_right) {
 		mdss_mdp_mixer_free(ctl->mixer_right);
 		ctl->mixer_right = NULL;
@@ -910,7 +917,7 @@
 			ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB888;
 			break;
 		}
-		mdss_mdp_dither_config(ctl, &dither, NULL);
+		mdss_mdp_dither_config(&dither, NULL);
 	}
 
 	return ctl;
@@ -1212,6 +1219,83 @@
 	return ret;
 }
 
+void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl,
+		struct mdp_display_commit *data)
+{
+	struct mdss_mdp_img_rect temp_roi, mixer_roi;
+
+	temp_roi.x = data->roi.x;
+	temp_roi.y = data->roi.y;
+	temp_roi.w = data->roi.w;
+	temp_roi.h = data->roi.h;
+
+	/*
+	 * No Partial Update for:
+	 * 1) dual DSI panels
+	 * 2) non-cmd mode panels
+	*/
+	if (!temp_roi.w || !temp_roi.h || ctl->mixer_right ||
+			(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL) ||
+			!ctl->panel_data->panel_info.partial_update_enabled) {
+		temp_roi = (struct mdss_mdp_img_rect)
+				{0, 0, ctl->mixer_left->width,
+					ctl->mixer_left->height};
+	}
+
+	ctl->roi_changed = 0;
+	if (((temp_roi.x != ctl->roi.x) ||
+			(temp_roi.y != ctl->roi.y)) ||
+			((temp_roi.w != ctl->roi.w) ||
+			 (temp_roi.h != ctl->roi.h))) {
+		ctl->roi = temp_roi;
+		ctl->roi_changed++;
+
+		mixer_roi = ctl->mixer_left->roi;
+		if ((mixer_roi.w != temp_roi.w) ||
+			(mixer_roi.h != temp_roi.h)) {
+			ctl->mixer_left->roi = temp_roi;
+			ctl->mixer_left->params_changed++;
+		}
+	}
+	pr_debug("ROI requested: [%d, %d, %d, %d]\n",
+			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)
 {
@@ -1220,12 +1304,24 @@
 	u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
 	u32 fg_alpha = 0, bg_alpha = 0;
 	int stage, secure = 0;
+	int screen_state;
+	int outsize = 0;
+
+	screen_state = ctl->force_screen_state;
 
 	if (!mixer)
 		return -ENODEV;
 
 	pr_debug("setup mixer=%d\n", mixer->num);
 
+	outsize = (mixer->roi.h << 16) | mixer->roi.w;
+	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+
+	if (screen_state == MDSS_SCREEN_FORCE_BLANK) {
+		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+		goto update_mixer;
+	}
+
 	pipe = mixer->stage_pipe[MDSS_MDP_STAGE_BASE];
 	if (pipe == NULL) {
 		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
@@ -1333,6 +1429,7 @@
 	if (mixer->cursor_enabled)
 		mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
 
+update_mixer:
 	pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
 
 	if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
@@ -1594,6 +1691,16 @@
 	return 0;
 }
 
+int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps)
+{
+	int ret = 0;
+
+	if (ctl->config_fps_fnc)
+		ret = ctl->config_fps_fnc(ctl, fps);
+
+	return ret;
+}
+
 int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
 				 ktime_t *wakeup_time)
 {
@@ -1732,7 +1839,8 @@
 	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	if (mixer1_changed || mixer2_changed) {
+	if (mixer1_changed || mixer2_changed
+			|| ctl->force_screen_state) {
 		perf_update = mdss_mdp_ctl_perf_update(ctl);
 
 		if (ctl->prepare_fnc)
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 213368a..940d6c9 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)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 920c231..e0717ad 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -43,13 +43,13 @@
 	struct mutex clk_mtx;
 	spinlock_t clk_lock;
 	struct work_struct clk_work;
-
 	/* te config */
 	u8 tear_check;
 	u16 height;	/* panel height */
 	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 +264,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;
@@ -428,6 +453,22 @@
 	return rc;
 }
 
+static int mdss_mdp_cmd_set_partial_roi(struct mdss_mdp_ctl *ctl)
+{
+	int rc = 0;
+	if (ctl->roi.w && ctl->roi.h && ctl->roi_changed &&
+			ctl->panel_data->panel_info.partial_update_enabled) {
+		ctl->panel_data->panel_info.roi_x = ctl->roi.x;
+		ctl->panel_data->panel_info.roi_y = ctl->roi.y;
+		ctl->panel_data->panel_info.roi_w = ctl->roi.w;
+		ctl->panel_data->panel_info.roi_h = ctl->roi.h;
+
+		rc = mdss_mdp_ctl_intf_event(ctl,
+				MDSS_EVENT_ENABLE_PARTIAL_UPDATE, NULL);
+	}
+	return rc;
+}
+
 int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
@@ -450,12 +491,15 @@
 		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
-	mdss_mdp_cmd_clk_on(ctx);
+	mdss_mdp_cmd_set_partial_roi(ctl);
 
 	/*
 	 * 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);
 
 	INIT_COMPLETION(ctx->pp_comp);
 	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
@@ -569,6 +613,9 @@
 	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
 	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 c78339a..a040785 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -16,6 +16,8 @@
 #include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
@@ -76,11 +78,15 @@
 
 static inline u32 mdss_mdp_video_line_count(struct mdss_mdp_ctl *ctl)
 {
-	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_video_ctx *ctx;
 	u32 line_cnt = 0;
+	if (!ctl || !ctl->priv_data)
+		goto line_count_exit;
+	ctx = ctl->priv_data;
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	line_cnt = mdp_video_read(ctx, MDSS_MDP_REG_INTF_LINE_COUNT);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+line_count_exit:
 	return line_cnt;
 }
 
@@ -109,7 +115,7 @@
 	return 0;
 }
 
-static int mdss_mdp_video_timegen_setup(struct mdss_mdp_video_ctx *ctx,
+static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
 					struct intf_timing_params *p)
 {
 	u32 hsync_period, vsync_period;
@@ -117,7 +123,9 @@
 	u32 active_h_start, active_h_end, active_v_start, active_v_end;
 	u32 den_polarity, hsync_polarity, vsync_polarity;
 	u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
+	struct mdss_mdp_video_ctx *ctx;
 
+	ctx = ctl->priv_data;
 	hsync_period = p->hsync_pulse_width + p->h_back_porch +
 			p->width + p->h_front_porch;
 	vsync_period = p->vsync_pulse_width + p->v_back_porch +
@@ -180,7 +188,7 @@
 
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
-			   vsync_period * hsync_period);
+			vsync_period * hsync_period);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0,
 			   p->vsync_pulse_width * hsync_period);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_DISPLAY_HCTL, display_hctl);
@@ -322,6 +330,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;
 
@@ -440,6 +449,88 @@
 			ctl->underrun_cnt);
 }
 
+static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
+{
+	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_panel_data *pdata;
+	int rc = 0;
+	u32 hsync_period, vsync_period;
+
+	pr_debug("Updating fps for ctl=%d\n", ctl->num);
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	pdata = ctl->panel_data;
+	if (pdata == NULL) {
+		pr_err("%s: Invalid panel data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!pdata->panel_info.dynamic_fps) {
+		pr_err("%s: Dynamic fps not enabled for this panel\n",
+						__func__);
+		return -EINVAL;
+	}
+
+	vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
+	hsync_period = mdss_panel_get_htotal(&pdata->panel_info);
+
+	if (pdata->panel_info.dfps_update
+			!= DFPS_SUSPEND_RESUME_MODE) {
+		if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+			if (!ctx->timegen_en) {
+				pr_err("TG is OFF. DFPS mode invalid\n");
+				return -EINVAL;
+			}
+			ctl->force_screen_state = MDSS_SCREEN_FORCE_BLANK;
+			mdss_mdp_display_commit(ctl, NULL);
+			mdss_mdp_display_wait4comp(ctl);
+			mdp_video_write(ctx,
+					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+			/*
+			 * Need to wait for atleast one vsync time for proper
+			 * TG OFF before doing changes on interfaces
+			 */
+			msleep(20);
+			rc = mdss_mdp_ctl_intf_event(ctl,
+						MDSS_EVENT_PANEL_UPDATE_FPS,
+						(void *)new_fps);
+			WARN(rc, "intf %d panel fps update error (%d)\n",
+							ctl->intf_num, rc);
+			mdp_video_write(ctx,
+					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
+			/*
+			 * Add memory barrier to make sure the MDP Video
+			 * mode engine is enabled before next frame is sent
+			 */
+			mb();
+			ctl->force_screen_state = MDSS_SCREEN_DEFAULT;
+			mdss_mdp_display_commit(ctl, NULL);
+			mdss_mdp_display_wait4comp(ctl);
+		} else {
+			pr_err("intf %d panel, unknown FPS mode\n",
+							ctl->intf_num);
+			return -EINVAL;
+		}
+	} else {
+		rc = mdss_mdp_ctl_intf_event(ctl,
+					MDSS_EVENT_PANEL_UPDATE_FPS,
+					(void *)new_fps);
+		WARN(rc, "intf %d panel fps update error (%d)\n",
+						ctl->intf_num, rc);
+	}
+
+	return rc;
+}
+
+
+
+
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -492,67 +583,13 @@
 	return 0;
 }
 
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
-{
-	void *virt = NULL;
-	unsigned long bl_fb_addr = 0;
-	unsigned long *bl_fb_addr_va;
-	unsigned long  pipe_addr, pipe_src_size;
-	u32 height, width, rgb_size, bpp;
-	size_t size;
-	static struct ion_handle *ihdl;
-	struct ion_client *iclient = mdss_get_ionclient();
-	static ion_phys_addr_t phys;
-
-	pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
-		MDSS_MDP_REG_SSPP_SRC0_ADDR;
-	pipe_src_size =
-		MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
-	bpp        = 3;
-	rgb_size   = MDSS_MDP_REG_READ(pipe_src_size);
-	bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
-	height = (rgb_size >> 16) & 0xffff;
-	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * width * bpp);
-	pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
-			__func__, __LINE__, height, width, size);
-
-	ihdl = ion_alloc(iclient, size, SZ_1M,
-			ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-	if (IS_ERR_OR_NULL(ihdl)) {
-		pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
-		return -ENOMEM;
-	}
-
-	pdata->panel_info.splash_ihdl = ihdl;
-
-	virt = ion_map_kernel(iclient, ihdl);
-	ion_phys(iclient, ihdl, &phys, &size);
-
-	pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
-			__func__, __LINE__, size,
-			(unsigned long int)virt, &phys);
-
-	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-	memcpy(virt, bl_fb_addr_va, size);
-	iounmap(bl_fb_addr_va);
-
-	MDSS_MDP_REG_WRITE(pipe_addr, phys);
-	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
-			0x48);
-
-	return 0;
-}
-
 int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
 {
-	struct ion_client *iclient = mdss_get_ionclient();
 	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_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
 
 	off = 0;
 
@@ -578,7 +615,12 @@
 			mdss_v2_intf_off, 0);
 	/* wait for 1 VSYNC for the pipe to be unstaged */
 	msleep(20);
-	ion_free(iclient, pdata->panel_info.splash_ihdl);
+
+	/* 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);
@@ -654,7 +696,7 @@
 			pinfo->bpp);
 	itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
 
-	if (mdss_mdp_video_timegen_setup(ctx, &itp)) {
+	if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
 		pr_err("unable to get timing parameters\n");
 		return -EINVAL;
 	}
@@ -666,6 +708,7 @@
 	ctl->read_line_cnt_fnc = mdss_mdp_video_line_count;
 	ctl->add_vsync_handler = mdss_mdp_video_add_vsync_handler;
 	ctl->remove_vsync_handler = mdss_mdp_video_remove_vsync_handler;
+	ctl->config_fps_fnc = mdss_mdp_video_config_fps;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 2b07428..7f872b4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -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 */
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 8e805da..1584925 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -22,11 +22,12 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/msm_mdp.h>
+#include <linux/memblock.h>
 
 #include <mach/iommu_domains.h>
 #include <mach/event_timer.h>
 #include <mach/msm_bus.h>
-
+#include <mach/scm.h>
 #include "mdss.h"
 #include "mdss_debug.h"
 #include "mdss_fb.h"
@@ -41,10 +42,37 @@
 #define PP_CLK_CFG_OFF 0
 #define PP_CLK_CFG_ON 1
 
+#define MEM_PROTECT_SD_CTRL 0xF
+
+struct sd_ctrl_req {
+	unsigned int enable;
+} __attribute__ ((__packed__));
+
 static atomic_t ov_active_panels = ATOMIC_INIT(0);
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd);
+
+static int mdss_mdp_overlay_sd_ctrl(struct msm_fb_data_type *mfd,
+					unsigned int enable)
+{
+	struct sd_ctrl_req request;
+	unsigned int resp = -1;
+	int ret = 0;
+	pr_debug("sd_ctrl %u\n", enable);
+
+	request.enable = enable;
+
+	ret = scm_call(SCM_SVC_MP, MEM_PROTECT_SD_CTRL,
+		&request, sizeof(request), &resp, sizeof(resp));
+	pr_debug("scm_call MEM_PROTECT_SD_CTRL(%u): ret=%d, resp=%x",
+				enable, ret, resp);
+	if (ret)
+		return ret;
+
+	return resp;
+}
 
 static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
@@ -387,7 +415,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) {
@@ -545,12 +573,11 @@
 					pipe->pp_cfg.hist_cfg.frame_cnt;
 				hist.bit_mask = pipe->pp_cfg.hist_cfg.bit_mask;
 				hist.num_bins = pipe->pp_cfg.hist_cfg.num_bins;
-				mdss_mdp_histogram_start(pipe->mixer->ctl,
-									&hist);
+				mdss_mdp_histogram_start(&hist);
 			} else if (pipe->pp_cfg.hist_cfg.ops &
 							MDP_PP_OPS_DISABLE) {
-				mdss_mdp_histogram_stop(pipe->mixer->ctl,
-						pipe->pp_cfg.hist_cfg.block);
+				mdss_mdp_histogram_stop(
+					pipe->pp_cfg.hist_cfg.block);
 			}
 		}
 		len = pipe->pp_cfg.hist_lut_cfg.len;
@@ -776,8 +803,11 @@
 	int rc;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	if (mdp5_data->ctl->power_on)
+	if (mdp5_data->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);
 
@@ -824,13 +854,15 @@
 	activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time);
 }
 
-int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
+				struct mdp_display_commit *data)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	struct mdss_mdp_pipe *pipe, *next;
+	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_ctl *tmp;
 	int ret;
+	int sd_in_pipe = 0;
 
 	if (ctl->shared_lock)
 		mutex_lock(ctl->shared_lock);
@@ -846,11 +878,41 @@
 			mutex_unlock(ctl->shared_lock);
 		return ret;
 	}
+	/*
+	 * check if there is a secure display session
+	 */
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
+		if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION) {
+			sd_in_pipe |= 1;
+			pr_debug("Secure pipe: %u : %08X\n",
+					pipe->num, pipe->flags);
+		}
+	}
+	/*
+	 * If there is no secure display session and sd_enabled, disable the
+	 * secure display session
+	 */
+	if (!sd_in_pipe && mdp5_data->sd_enabled) {
+		if (0 == mdss_mdp_overlay_sd_ctrl(mfd, 0))
+			mdp5_data->sd_enabled = 0;
+	}
 
-	list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
-			used_list) {
+	if (data)
+		mdss_mdp_set_roi(ctl, data);
+
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		/*
+		 * When secure display is enabled, if there is a non secure
+		 * display pipe, skip that
+		 */
+		if ((mdp5_data->sd_enabled) &&
+			!(pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION)) {
+			pr_warn("Non secure pipe during secure display: %u: %08X, skip\n",
+					pipe->num, pipe->flags);
+			continue;
+		}
+		/*
 		 * When external is connected and no dedicated wfd is present,
 		 * reprogram DMA pipe before kickoff to clear out any previous
 		 * block mode configuration.
@@ -886,12 +948,6 @@
 			pipe->params_changed++;
 			buf = &pipe->front_buf;
 		} else if (!pipe->params_changed) {
-			if (pipe->mixer && !mdss_mdp_pipe_is_staged(pipe) &&
-			    !list_empty(&pipe->used_list)) {
-				list_del_init(&pipe->used_list);
-				list_add(&pipe->cleanup_list,
-					&mdp5_data->pipes_cleanup);
-			}
 			continue;
 		} else if (pipe->front_buf.num_planes) {
 			buf = &pipe->front_buf;
@@ -922,6 +978,16 @@
 
 	ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
 
+	if (ret == 0) {
+		mutex_lock(&mfd->lock);
+		if (!mdp5_data->sd_enabled && (sd_in_pipe == 1)) {
+			ret = mdss_mdp_overlay_sd_ctrl(mfd, 1);
+			if (ret == 0)
+				mdp5_data->sd_enabled = 1;
+		}
+		mutex_unlock(&mfd->lock);
+	}
+
 	mdss_fb_update_notify_update(mfd);
 commit_fail:
 	mdss_mdp_overlay_cleanup(mfd);
@@ -1038,7 +1104,7 @@
 	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
-		if (pipe->pid == pid) {
+		if (!mfd->ref_cnt || (pipe->pid == pid)) {
 			unset_ndx |= pipe->ndx;
 			cnt++;
 		}
@@ -1059,7 +1125,7 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 
 	if (cnt)
-		mfd->mdp.kickoff_fnc(mfd);
+		mfd->mdp.kickoff_fnc(mfd, NULL);
 
 	list_for_each_entry_safe(rot, tmp, &mdp5_data->rot_proc_list, list) {
 		if (rot->pid == pid) {
@@ -1080,7 +1146,7 @@
 	if (!mfd)
 		return -ENODEV;
 
-	ret = mfd->mdp.kickoff_fnc(mfd);
+	ret = mfd->mdp.kickoff_fnc(mfd, NULL);
 	if (!ret)
 		pr_err("error displaying\n");
 
@@ -1102,6 +1168,12 @@
 
 	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) {
@@ -1117,7 +1189,7 @@
 		goto dst_buf_fail;
 	}
 
-	ret = mdss_mdp_rotator_queue(rot, &rot->src_buf, &rot->dst_buf);
+	ret = mdss_mdp_rotator_queue(rot);
 	if (ret)
 		pr_err("rotator queue error session id=%x\n", req->id);
 
@@ -1143,6 +1215,7 @@
 	pr_debug("ov queue pnum=%d\n", pipe->num);
 
 	flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION);
+	flags |= (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION);
 
 	src_data = &pipe->back_buf;
 	if (src_data->num_planes) {
@@ -1343,7 +1416,7 @@
 
 	if (!fbi->fix.smem_start || fbi->fix.smem_len == 0 ||
 	     mdp5_data->borderfill_enable) {
-		mfd->mdp.kickoff_fnc(mfd);
+		mfd->mdp.kickoff_fnc(mfd, NULL);
 		return;
 	}
 
@@ -1417,7 +1490,7 @@
 
 	if ((fbi->var.activate & FB_ACTIVATE_VBL) ||
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
-		mfd->mdp.kickoff_fnc(mfd);
+		mfd->mdp.kickoff_fnc(mfd, NULL);
 
 	return;
 
@@ -1454,14 +1527,9 @@
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
 		return -EOPNOTSUPP;
 
-	rc = mutex_lock_interruptible(&ctl->lock);
-	if (rc)
-		return rc;
-
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mutex_unlock(&ctl->lock);
 		return -EPERM;
 	}
 
@@ -1474,11 +1542,99 @@
 		rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
-	mutex_unlock(&ctl->lock);
-
 	return rc;
 }
 
+static ssize_t dynamic_fps_sysfs_rda_dfps(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+		return 0;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n",
+		       pdata->panel_info.mipi.frame_rate);
+	pr_debug("%s: '%d'\n", __func__,
+		pdata->panel_info.mipi.frame_rate);
+
+	return ret;
+} /* dynamic_fps_sysfs_rda_dfps */
+
+static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int dfps, rc = 0;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	rc = kstrtoint(buf, 10, &dfps);
+	if (rc) {
+		pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+		return 0;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	if (dfps == pdata->panel_info.mipi.frame_rate) {
+		pr_debug("%s: FPS is already %d\n",
+			__func__, dfps);
+		return count;
+	}
+
+	if (dfps < 30) {
+		pr_err("Unsupported FPS. Configuring to min_fps = 30\n");
+		dfps = 30;
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	} else if (dfps > 60) {
+		pr_err("Unsupported FPS. Configuring to max_fps = 60\n");
+		dfps = 60;
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	} else {
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	}
+	if (!rc) {
+		pr_info("%s: configured to '%d' FPS\n", __func__, dfps);
+	} else {
+		pr_err("Failed to configure '%d' FPS. rc = %d\n",
+							dfps, rc);
+		return rc;
+	}
+	pdata->panel_info.new_fps = dfps;
+	return count;
+} /* dynamic_fps_sysfs_wta_dfps */
+
+
+static DEVICE_ATTR(dynamic_fps, S_IRUGO | S_IWUSR, dynamic_fps_sysfs_rda_dfps,
+	dynamic_fps_sysfs_wta_dfps);
+
+static struct attribute *dynamic_fps_fs_attrs[] = {
+	&dev_attr_dynamic_fps.attr,
+	NULL,
+};
+static struct attribute_group dynamic_fps_fs_attrs_group = {
+	.attrs = dynamic_fps_fs_attrs,
+};
+
 static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -1734,7 +1890,6 @@
 	struct msmfb_mdp_pp mdp_pp;
 	u32 copyback = 0;
 	u32 copy_from_kernel = 0;
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
 	if (ret)
@@ -1749,14 +1904,12 @@
 
 	switch (mdp_pp.op) {
 	case mdp_op_pa_cfg:
-		ret = mdss_mdp_pa_config(mdp5_data->ctl,
-					&mdp_pp.data.pa_cfg_data,
+		ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
 					&copyback);
 		break;
 
 	case mdp_op_pcc_cfg:
-		ret = mdss_mdp_pcc_config(mdp5_data->ctl,
-					&mdp_pp.data.pcc_cfg_data,
+		ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
 					&copyback);
 		break;
 
@@ -1764,7 +1917,6 @@
 		switch (mdp_pp.data.lut_cfg_data.lut_type) {
 		case mdp_lut_igc:
 			ret = mdss_mdp_igc_lut_config(
-					mdp5_data->ctl,
 					(struct mdp_igc_lut_data *)
 					&mdp_pp.data.lut_cfg_data.data,
 					&copyback, copy_from_kernel);
@@ -1772,14 +1924,12 @@
 
 		case mdp_lut_pgc:
 			ret = mdss_mdp_argc_config(
-				mdp5_data->ctl,
 				&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
 				&copyback);
 			break;
 
 		case mdp_lut_hist:
 			ret = mdss_mdp_hist_lut_config(
-				mdp5_data->ctl,
 				(struct mdp_hist_lut_data *)
 				&mdp_pp.data.lut_cfg_data.data, &copyback);
 			break;
@@ -1791,13 +1941,11 @@
 		break;
 	case mdp_op_dither_cfg:
 		ret = mdss_mdp_dither_config(
-				mdp5_data->ctl,
 				&mdp_pp.data.dither_cfg_data,
 				&copyback);
 		break;
 	case mdp_op_gamut_cfg:
 		ret = mdss_mdp_gamut_config(
-				mdp5_data->ctl,
 				&mdp_pp.data.gamut_cfg_data,
 				&copyback);
 		break;
@@ -1848,7 +1996,6 @@
 	struct mdp_histogram_data hist;
 	struct mdp_histogram_start_req hist_req;
 	u32 block;
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 pp_bus_handle;
 	static int req = -1;
 
@@ -1867,7 +2014,7 @@
 		if (ret)
 			return ret;
 
-		ret = mdss_mdp_histogram_start(mdp5_data->ctl, &hist_req);
+		ret = mdss_mdp_histogram_start(&hist_req);
 		break;
 
 	case MSMFB_HISTOGRAM_STOP:
@@ -1875,7 +2022,7 @@
 		if (ret)
 			return ret;
 
-		ret = mdss_mdp_histogram_stop(mdp5_data->ctl, block);
+		ret = mdss_mdp_histogram_stop(block);
 		if (ret)
 			return ret;
 
@@ -1897,7 +2044,7 @@
 		if (ret)
 			return ret;
 
-		ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist);
+		ret = mdss_mdp_hist_collect(&hist);
 		if (!ret)
 			ret = copy_to_user(argp, &hist, sizeof(hist));
 		break;
@@ -2081,9 +2228,9 @@
 		}
 		break;
 	case MSMFB_OVERLAY_COMMIT:
-		mdss_fb_wait_for_fence(mfd);
-		ret = mfd->mdp.kickoff_fnc(mfd);
-		mdss_fb_signal_timeline(mfd);
+		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));
@@ -2158,7 +2305,7 @@
 		(mfd->panel_info->type != WRITEBACK_PANEL)) {
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc))
-			rc = mdss_mdp_overlay_kickoff(mfd);
+			rc = mdss_mdp_overlay_kickoff(mfd, NULL);
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
 		if (rc)
@@ -2211,7 +2358,7 @@
 
 	if (need_cleanup) {
 		pr_debug("cleaning up pipes on fb%d\n", mfd->index);
-		mdss_mdp_overlay_kickoff(mfd);
+		mdss_mdp_overlay_kickoff(mfd, NULL);
 	}
 
 	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
@@ -2244,7 +2391,6 @@
 	if (pdata->panel_info.cont_splash_enabled) {
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		mdss_mdp_footswitch_ctrl_splash(1);
-		mdss_mdp_ctl_splash_start(pdata);
 	}
 	return 0;
 }
@@ -2265,6 +2411,7 @@
 	mdp5_interface->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
 	mdp5_interface->panel_register_done = mdss_panel_register_done;
 	mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
+	mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
 
 	mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
 	if (!mdp5_data) {
@@ -2306,6 +2453,15 @@
 		goto init_fail;
 	}
 
+	if (mfd->panel_info->type == MIPI_VIDEO_PANEL) {
+		rc = sysfs_create_group(&dev->kobj,
+			&dynamic_fps_fs_attrs_group);
+		if (rc) {
+			pr_err("Error dfps sysfs creation ret=%d\n", rc);
+			goto init_fail;
+		}
+	}
+
 	pm_runtime_set_suspended(&mfd->pdev->dev);
 	pm_runtime_enable(&mfd->pdev->dev);
 
@@ -2322,8 +2478,48 @@
 	return rc;
 }
 
+static __ref int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
+	int len = 0, rc = 0;
+	u32 offsets[2];
+
+	of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len);
+
+	if (len < 1) {
+		pr_debug("mem reservation for splash screen fb not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	len = len/sizeof(u32);
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,memblock-reserve", offsets, len);
+	if (rc) {
+		pr_debug("Error reading mem reserve settings for fb\n");
+		goto error;
+	}
+
+	if (!memblock_is_reserved(offsets[0])) {
+		pr_debug("failed to reserve memory for fb splash\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	mdp5_mdata->splash_mem_addr = offsets[0];
+	mdp5_mdata->splash_mem_size = offsets[1];
+	pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr,
+		mdp5_mdata->splash_mem_size);
+
+error:
+	return rc;
+}
+
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd)
 {
+	int rc = 0;
 	struct platform_device *pdev = mfd->pdev;
 	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
 
@@ -2334,5 +2530,13 @@
 			pdev->name);
 	}
 
-	return 0;
+	rc = mdss_mdp_overlay_splash_parse_dt(mfd);
+	if (rc && mfd->panel_info->cont_splash_enabled) {
+		pr_err("No rsvd mem found in DT for splash screen\n");
+	} else {
+		pr_debug("Mem reservation not reqd if cont splash diasbled\n");
+		rc = 0;
+	}
+
+	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 3f75053..c18fd9b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -173,21 +173,39 @@
 			return rc;
 		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
 			ps.ystride[0], ps.ystride[1]);
-	} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
-		ps.num_planes = 2;
-		ps.ystride[0] = width;
-		ps.ystride[1] = ps.ystride[0];
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
 			width, pipe->src.h, &ps, 0);
 		if (rc)
 			return rc;
 
-		if (pipe->mixer && pipe->mixer->rotator_mode)
+		if (pipe->mixer && pipe->mixer->rotator_mode) {
 			rot_mode = 1;
-		else if (ps.num_planes == 1)
+		} else if (ps.num_planes == 1) {
 			ps.ystride[0] = MAX_BPP *
 				max(pipe->mixer->width, width);
+		} else if (mdata->has_decimation) {
+			/*
+			 * when decimation block is used, all chroma planes
+			 * are fetched on a single SMP plane for chroma pixels
+			 */
+			if (ps.num_planes == 3) {
+				ps.num_planes = 2;
+				ps.ystride[1] += ps.ystride[2];
+			}
+
+			/*
+			 * To avoid quailty loss, MDP does one less decimation
+			 * on chroma components if they are subsampled.
+			 * Account for this to have enough SMPs for latency
+			 */
+			switch (pipe->src_fmt->chroma_sample) {
+			case MDSS_MDP_CHROMA_H2V1:
+			case MDSS_MDP_CHROMA_420:
+				ps.ystride[1] <<= 1;
+				break;
+			}
+		}
 	}
 
 	nlines = pipe->bwc_mode ? 1 : 2;
@@ -289,7 +307,7 @@
 static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer,
 						u32 type, u32 off)
 {
-	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_pipe *pipe = NULL;
 	struct mdss_data_type *mdata;
 	struct mdss_mdp_pipe *pipe_pool = NULL;
 	u32 npipes;
@@ -463,22 +481,51 @@
 
 }
 
-static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
+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)
+{
+	struct mdss_mdp_img_rect res;
+	mdss_mdp_intersect_rect(&res, dst_rect, sci_rect);
+
+	if (res.w && res.h) {
+		if ((res.w != dst_rect->w) || (res.h != dst_rect->h)) {
+			src_rect->x = src_rect->x + (res.x - dst_rect->x);
+			src_rect->y = src_rect->y + (res.y - dst_rect->y);
+			src_rect->w = res.w;
+			src_rect->h = res.h;
+		}
+		*dst_rect = (struct mdss_mdp_img_rect)
+			{(res.x - sci_rect->x), (res.y - sci_rect->y),
+			res.w, res.h};
+	}
+}
+
+static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe,
+					struct mdss_mdp_data *data)
 {
 	u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
 	u32 width, height;
 	u32 decimation;
+	struct mdss_mdp_img_rect sci, dst, src;
+	int ret = 0;
 
 	pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
-		   pipe->num, pipe->img_width, pipe->img_height,
-		   pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
-		   pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
+			pipe->num, pipe->img_width, pipe->img_height,
+			pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
+			pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
 
 	width = pipe->img_width;
 	height = pipe->img_height;
 	mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height,
 			&pipe->src_planes, pipe->bwc_mode);
 
+	if (data != NULL) {
+		ret = mdss_mdp_data_check(data, &pipe->src_planes);
+		if (ret)
+			return ret;
+	}
+
 	if ((pipe->flags & MDP_DEINTERLACE) &&
 			!(pipe->flags & MDP_SOURCE_ROTATED_90)) {
 		int i;
@@ -494,15 +541,23 @@
 		pr_debug("Image decimation h=%d v=%d\n",
 				pipe->horz_deci, pipe->vert_deci);
 
+	sci = pipe->mixer->ctl->roi;
+	dst = pipe->dst;
+	src = pipe->src;
+
+	mdss_mdp_crop_rect(&src, &dst, &sci);
+
+	src_size = (src.h << 16) | src.w;
+	src_xy = (src.y << 16) | src.x;
+	dst_size = (dst.h << 16) | dst.w;
+	dst_xy = (dst.y << 16) | dst.x;
+
 	img_size = (height << 16) | width;
-	src_size = (pipe->src.h << 16) | pipe->src.w;
-	src_xy = (pipe->src.y << 16) | pipe->src.x;
-	dst_size = (pipe->dst.h << 16) | pipe->dst.w;
-	dst_xy = (pipe->dst.y << 16) | pipe->dst.x;
+
 	ystride0 =  (pipe->src_planes.ystride[0]) |
-		    (pipe->src_planes.ystride[1] << 16);
+			(pipe->src_planes.ystride[1] << 16);
 	ystride1 =  (pipe->src_planes.ystride[2]) |
-		    (pipe->src_planes.ystride[3] << 16);
+			(pipe->src_planes.ystride[3] << 16);
 
 	if (pipe->overfetch_disable) {
 		img_size = src_size;
@@ -643,7 +698,7 @@
 
 	pr_debug("solid fill setup on pnum=%d\n", pipe->num);
 
-	ret = mdss_mdp_image_setup(pipe);
+	ret = mdss_mdp_image_setup(pipe, NULL);
 	if (ret) {
 		pr_err("image setup error for pnum=%d\n", pipe->num);
 		return ret;
@@ -688,7 +743,8 @@
 	params_changed = (pipe->params_changed) ||
 			 ((pipe->type == MDSS_MDP_PIPE_TYPE_DMA) &&
 			 (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
-			 && (ctl->mdata->mixer_switched));
+			 && (ctl->mdata->mixer_switched)) ||
+			 ctl->roi_changed;
 	if (src_data == NULL) {
 		mdss_mdp_pipe_solidfill_setup(pipe);
 		goto update_nobuf;
@@ -703,7 +759,7 @@
 			goto done;
 		}
 
-		ret = mdss_mdp_image_setup(pipe);
+		ret = mdss_mdp_image_setup(pipe, src_data);
 		if (ret) {
 			pr_err("image setup error for pnum=%d\n", pipe->num);
 			goto done;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0b64870..563a4a6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -295,6 +295,9 @@
 				struct mdp_pgc_lut_data *config);
 static void pp_update_hist_lut(char __iomem *base,
 				struct mdp_hist_lut_data *cfg);
+static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config);
+static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
+				u32 base, struct pp_sts_type *pp_sts);
 static void pp_pa_config(unsigned long flags, u32 base,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pa_cfg *pa_config);
@@ -1133,7 +1136,7 @@
 
 flush_exit:
 	writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE);
-	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num));
+	ctl->flush_bits |= BIT(13 + dspp_num);
 	wmb();
 dspp_exit:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -1369,15 +1372,12 @@
 	return 0;
 }
 
-int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl, struct mdp_pa_cfg_data *config,
+int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config,
 			u32 *copyback)
 {
 	int ret = 0;
 	u32 pa_offset, disp_num, dspp_num = 0;
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -1411,8 +1411,6 @@
 
 pa_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 
@@ -1542,16 +1540,12 @@
 	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
 }
 
-int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
-					struct mdp_pcc_cfg_data *config,
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config,
 					u32 *copyback)
 {
 	int ret = 0;
 	u32 base, disp_num, dspp_num = 0;
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -1581,8 +1575,6 @@
 
 pcc_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 
@@ -1656,22 +1648,18 @@
 	config.c0_c1_data = igc_limited;
 	config.c2_data = igc_limited;
 
-	ret = mdss_mdp_igc_lut_config(ctl, &config, &copyback,
+	ret = mdss_mdp_igc_lut_config(&config, &copyback,
 					copy_from_kernel);
 	return ret;
 }
 
-int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
-					struct mdp_igc_lut_data *config,
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config,
 					u32 *copyback, u32 copy_from_kernel)
 {
 	int ret = 0;
 	u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
 	struct mdp_igc_lut_data local_cfg;
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -1748,8 +1736,6 @@
 
 igc_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 static void pp_update_gc_one_lut(u32 offset,
@@ -1864,8 +1850,7 @@
 		writel_relaxed(1, offset + 16);
 }
 
-int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
-				struct mdp_pgc_lut_data *config,
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config,
 				u32 *copyback)
 {
 	int ret = 0;
@@ -1874,9 +1859,6 @@
 	struct mdp_pgc_lut_data *pgc_ptr;
 	u32 tbl_size, r_size, g_size, b_size;
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -1986,20 +1968,14 @@
 	}
 argc_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
-int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
-					struct mdp_hist_lut_data *config,
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config,
 					u32 *copyback)
 {
 	int i, ret = 0;
 	u32 hist_offset, disp_num, dspp_num = 0;
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -2043,18 +2019,13 @@
 	}
 enhist_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 
-int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
-					struct mdp_dither_cfg_data *config,
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config,
 					u32 *copyback)
 {
 	u32 disp_num;
-	if (!ctl)
-		return -EINVAL;
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
@@ -2067,15 +2038,35 @@
 	mdss_pp_res->dither_disp_cfg[disp_num] = *config;
 	mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
 	mutex_unlock(&mdss_pp_mutex);
-	mdss_mdp_pp_setup(ctl);
 	return 0;
 }
 
-int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
-					struct mdp_gamut_cfg_data *config,
+static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config)
+{
+	if (config->tbl_size[0] != GAMUT_T0_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[1] != GAMUT_T1_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[2] != GAMUT_T2_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[3] != GAMUT_T3_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[4] != GAMUT_T4_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[5] != GAMUT_T5_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[6] != GAMUT_T6_SIZE)
+		return -EINVAL;
+	if (config->tbl_size[7] != GAMUT_T7_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config,
 					u32 *copyback)
 {
-	int i, j, size_total = 0, ret = 0;
+	int i, j, ret = 0;
 	u32 offset, disp_num, dspp_num = 0;
 	uint16_t *tbl_off;
 	struct mdp_gamut_cfg_data local_cfg;
@@ -2084,15 +2075,11 @@
 	uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
 
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
-	for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++)
-		size_total += config->tbl_size[i];
-	if (size_total != GAMUT_TOTAL_TABLE_SIZE)
+
+	if (pp_gm_has_invalid_lut_size(config))
 		return -EINVAL;
 
 	mutex_lock(&mdss_pp_mutex);
@@ -2209,8 +2196,6 @@
 	}
 gamut_config_exit:
 	mutex_unlock(&mdss_pp_mutex);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 static void pp_hist_read(char __iomem *v_base,
@@ -2253,7 +2238,7 @@
 	hist_info->col_state = HIST_RESET;
 	hist_info->col_en = true;
 	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
-	hist_info->is_kick_ready = false;
+	hist_info->is_kick_ready = true;
 	mdss_mdp_hist_irq_enable(3 << shift_bit);
 	writel_relaxed(req->frame_cnt, ctl_base + 8);
 	/* Kick out reset start */
@@ -2263,8 +2248,7 @@
 	return ret;
 }
 
-int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_start_req *req)
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
 {
 	u32 done_shift_bit;
 	char __iomem *ctl_base;
@@ -2274,8 +2258,6 @@
 	u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
-	if (!ctl)
-		return -EINVAL;
 
 	if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(req->block) >= MDP_BLOCK_MAX))
@@ -2342,31 +2324,6 @@
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 hist_exit:
-	if (!ret && (PP_LOCAT(req->block) == MDSS_PP_DSPP_CFG)) {
-		mdss_mdp_pp_setup(ctl);
-		/* wait for a frame to let histrogram enable itself */
-		/* TODO add hysteresis value to be able to remove this sleep */
-		usleep(41666);
-		for (i = 0; i < mixer_cnt; i++) {
-			dspp_num = mixer_id[i];
-			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-			mutex_lock(&hist_info->hist_mutex);
-			hist_info->is_kick_ready = true;
-			mutex_unlock(&hist_info->hist_mutex);
-		}
-	} else if (!ret) {
-		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
-			if (!PP_ARG(i, req->block))
-				continue;
-			pr_info("PP_ARG(%d) = %d", i, PP_ARG(i, req->block));
-			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
-			if (IS_ERR_OR_NULL(pipe))
-				continue;
-			hist_info = &pipe->pp_res.hist;
-			hist_info->is_kick_ready = true;
-			mdss_mdp_pipe_unmap(pipe);
-		}
-	}
 	return ret;
 }
 
@@ -2395,7 +2352,7 @@
 	return ret;
 }
 
-int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
+int mdss_mdp_histogram_stop(u32 block)
 {
 	int i, ret = 0;
 	char __iomem *ctl_base;
@@ -2405,9 +2362,6 @@
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((PP_BLOCK(block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -2472,13 +2426,10 @@
 hist_stop_clk:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 hist_stop_exit:
-	if (!ret && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG))
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 
-static int pp_hist_collect(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_data *hist,
+static int pp_hist_collect(struct mdp_histogram_data *hist,
 				struct pp_hist_col_info *hist_info,
 				char __iomem *ctl_base)
 {
@@ -2502,9 +2453,6 @@
 		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
 		mutex_unlock(&hist_info->hist_mutex);
-		/* flush updates before wait*/
-		if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG)
-			mdss_mdp_pp_setup(ctl);
 		if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) {
 			res = container_of(hist_info, struct mdss_pipe_pp_res,
 						hist);
@@ -2565,8 +2513,7 @@
 	return ret;
 }
 
-int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
-					struct mdp_histogram_data *hist)
+int mdss_mdp_hist_collect(struct mdp_histogram_data *hist)
 {
 	int i, j, off, ret = 0;
 	struct pp_hist_col_info *hist_info;
@@ -2580,9 +2527,6 @@
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
-	if (!ctl)
-		return -EINVAL;
-
 	if ((PP_BLOCK(hist->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(hist->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -2609,7 +2553,7 @@
 			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
 			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
 				MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
-			ret = pp_hist_collect(ctl, hist, hist_info, ctl_base);
+			ret = pp_hist_collect(hist, hist_info, ctl_base);
 			if (ret)
 				goto hist_collect_exit;
 		}
@@ -2678,7 +2622,7 @@
 			hist_info = &pipe->pp_res.hist;
 			ctl_base = pipe->base +
 				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
-			ret = pp_hist_collect(ctl, hist, hist_info, ctl_base);
+			ret = pp_hist_collect(hist, hist_info, ctl_base);
 			mdss_mdp_pipe_unmap(pipe);
 			if (ret)
 				goto hist_collect_exit;
@@ -2836,7 +2780,7 @@
 		return -EHOSTDOWN;
 	}
 	if (mixer_num > MDSS_AD_MAX_MIXERS) {
-		pr_warn("too many mixers, not supported, %d", mixer_num);
+		pr_debug("too many mixers, not supported, %d", mixer_num);
 		return ret;
 	}
 
@@ -2971,8 +2915,6 @@
 	}
 	mutex_unlock(&ad->lock);
 	ctl = mfd_to_ctl(mfd);
-	if (!ret)
-		mdss_mdp_pp_setup(ctl);
 	return ret;
 }
 
@@ -2980,7 +2922,6 @@
 			struct mdss_ad_input *input, int wait) {
 	int ret = 0;
 	struct mdss_ad_info *ad;
-	struct mdss_mdp_ctl *ctl;
 	u32 bl;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
@@ -3056,8 +2997,6 @@
 			init_completion(&ad->comp);
 			mutex_unlock(&ad->lock);
 		}
-		ctl = mfd_to_ctl(mfd);
-		mdss_mdp_pp_setup(ctl);
 		if (wait) {
 			ret = wait_for_completion_interruptible_timeout(
 					&ad->comp, HIST_WAIT_TIMEOUT(1));
@@ -3195,6 +3134,7 @@
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct msm_fb_data_type *bl_mfd;
 	char __iomem *base;
+	u32 temp;
 	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
@@ -3263,6 +3203,21 @@
 		pp_ad_init_write(ad);
 	}
 
+	/* update ad screen size if it has changed since last configuration */
+	if (mfd->panel_info->type == WRITEBACK_PANEL &&
+		(ad->init.frame_w != ctl->width ||
+			ad->init.frame_h != ctl->height)) {
+		pr_debug("changing from %dx%d to %dx%d", ad->init.frame_w,
+							ad->init.frame_h,
+							ctl->width,
+							ctl->height);
+		ad->init.frame_w = ctl->width;
+		ad->init.frame_h = ctl->height;
+		temp = ad->init.frame_w << 16;
+		temp |= ad->init.frame_h & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+	}
+
 	if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
 		bypass = 0;
 		ret = 1;
@@ -3399,7 +3354,7 @@
 	}
 	mutex_unlock(&ad->lock);
 	mutex_lock(&mfd->lock);
-	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + ad->num));
+	ctl->flush_bits |= BIT(13 + ad->num);
 	mutex_unlock(&mfd->lock);
 
 	/* Trigger update notify to wake up those waiting for display updates */
@@ -3555,12 +3510,22 @@
 int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
 						u32 *copyback)
 {
-	int ret = -1;
-	int counter = cfg->size / (sizeof(uint32_t) * 2);
+	int ret = -1, counter;
 	uint32_t *buff = NULL, *buff_org = NULL;
 	void *ptr;
 	int i = 0;
 
+	if (!cfg) {
+		pr_err("Invalid buffer pointer");
+		return ret;
+	}
+
+	if (cfg->size == 0) {
+		pr_err("Invalid buffer size");
+		return ret;
+	}
+
+	counter = cfg->size / (sizeof(uint32_t) * 2);
 	buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
 	if (buff == NULL) {
 		pr_err("Allocation failed");
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 8381c5b..44734f8 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -17,9 +17,12 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
 
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
+#include "mdss_fb.h"
 
 #define MAX_ROTATOR_SESSIONS 8
 
@@ -28,6 +31,11 @@
 static LIST_HEAD(rotator_queue);
 
 static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot);
+static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work);
+static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot);
+static int mdss_mdp_rotator_queue_helper(struct mdss_mdp_rotator_session *rot);
+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)
 {
@@ -67,6 +75,22 @@
 	return NULL;
 }
 
+struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_get(
+	struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync)
+{
+	struct mdss_mdp_rotator_session *rot;
+
+	rot = mdss_mdp_rotator_session_get(buf_sync->session_id);
+	if (!rot)
+		return NULL;
+	if (!rot->rot_sync_pt_data)
+		rot->rot_sync_pt_data = mdss_mdp_rotator_sync_pt_create(rot);
+	if (rot->rot_sync_pt_data)
+		rot->use_sync_pt = true;
+
+	return rot->rot_sync_pt_data;
+}
+
 static struct mdss_mdp_pipe *mdss_mdp_rotator_pipe_alloc(void)
 {
 	struct mdss_mdp_mixer *mixer;
@@ -246,21 +270,84 @@
 	return ret;
 }
 
-int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
-			   struct mdss_mdp_data *src_data,
-			   struct mdss_mdp_data *dst_data)
+static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work)
+{
+	struct mdss_mdp_rotator_session *rot;
+	int ret;
+
+	rot = container_of(work, struct mdss_mdp_rotator_session, commit_work);
+	ret = mdss_mdp_rotator_queue_helper(rot);
+
+	if (ret) {
+		pr_err("rotator queue failed\n");
+		return;
+	}
+
+	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");
+}
+
+static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
+				struct mdss_mdp_rotator_session *rot)
+{
+	struct msm_sync_pt_data *sync_pt_data;
+	char timeline_name[16];
+
+	rot->rot_sync_pt_data = kzalloc(
+		sizeof(struct msm_sync_pt_data), GFP_KERNEL);
+	sync_pt_data = rot->rot_sync_pt_data;
+	if (!sync_pt_data)
+		return NULL;
+	sync_pt_data->fence_name = "rot-fence";
+	sync_pt_data->threshold = 1;
+	snprintf(timeline_name, sizeof(timeline_name),
+					"mdss_rot_%d", rot->session_id);
+	sync_pt_data->timeline = sw_sync_timeline_create(timeline_name);
+	if (sync_pt_data->timeline == NULL) {
+		kfree(rot->rot_sync_pt_data);
+		pr_err("%s: cannot create time line", __func__);
+		return NULL;
+	} else {
+		sync_pt_data->timeline_value = 0;
+	}
+	INIT_WORK(&rot->commit_work,
+				mdss_mdp_rotator_commit_wq_handler);
+	mutex_init(&sync_pt_data->sync_mutex);
+	return sync_pt_data;
+}
+
+int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot)
+{
+
+	struct mdss_mdp_rotator_session *tmp;
+
+	for (tmp = rot; tmp; tmp = tmp->next)
+		mdss_mdp_rotator_busy_wait(tmp);
+
+	if (rot->use_sync_pt)
+		mdss_fb_wait_for_fence(rot->rot_sync_pt_data);
+
+	return 0;
+}
+
+static int mdss_mdp_rotator_queue_helper(struct mdss_mdp_rotator_session *rot)
 {
 	int ret;
-	struct mdss_mdp_rotator_session *tmp = rot;
+	struct mdss_mdp_rotator_session *tmp;
 
 	ret = mutex_lock_interruptible(&rotator_lock);
-	if (ret)
+	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, src_data, dst_data);
+		ret = mdss_mdp_rotator_queue_sub(tmp,
+				&rot->src_buf, &rot->dst_buf);
 
 	mutex_unlock(&rotator_lock);
 
@@ -272,6 +359,18 @@
 	for (tmp = rot; tmp; tmp = tmp->next)
 		mdss_mdp_rotator_busy_wait(tmp);
 
+	return ret;
+}
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot)
+{
+	int ret = 0;
+
+	if (rot->use_sync_pt)
+		schedule_work(&rot->commit_work);
+	else
+		ret = mdss_mdp_rotator_queue_helper(rot);
+
 	pr_debug("rotator session=%x queue done\n", rot->session_id);
 
 	return ret;
@@ -370,6 +469,8 @@
 	struct mdss_mdp_pipe *rot_pipe;
 	struct mdss_mdp_ctl *tmp;
 	int ret = 0;
+	struct msm_sync_pt_data *rot_sync_pt_data;
+	struct work_struct commit_work;
 
 	if (!rot)
 		return -ENODEV;
@@ -384,7 +485,13 @@
 		mdss_mdp_rotator_busy_wait(rot);
 		list_del(&rot->head);
 	}
+
+	rot_sync_pt_data = rot->rot_sync_pt_data;
+	commit_work = rot->commit_work;
 	memset(rot, 0, sizeof(*rot));
+	rot->rot_sync_pt_data = rot_sync_pt_data;
+	rot->commit_work = commit_work;
+
 	if (rot_pipe) {
 		struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
 		mdss_mdp_pipe_unmap(rot_pipe);
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 74eeeeb..ab7cce1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -43,18 +43,29 @@
 	struct mdss_mdp_data src_buf;
 	struct mdss_mdp_data dst_buf;
 
+	bool use_sync_pt;
 	struct list_head head;
 	struct list_head list;
 	struct mdss_mdp_rotator_session *next;
+	struct msm_sync_pt_data *rot_sync_pt_data;
+	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:
@@ -68,11 +79,10 @@
 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,
-			   struct mdss_mdp_data *src_data,
-			   struct mdss_mdp_data *dst_data);
-
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot);
 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);
 #endif /* MDSS_MDP_ROTATOR_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b65d894..1170d1e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -237,6 +237,20 @@
 	return NULL;
 }
 
+void mdss_mdp_intersect_rect(struct mdss_mdp_img_rect *res_rect,
+	const struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect)
+{
+	int l = max(dst_rect->x, sci_rect->x);
+	int t = max(dst_rect->y, sci_rect->y);
+	int r = min((dst_rect->x + dst_rect->w), (sci_rect->x + sci_rect->w));
+	int b = min((dst_rect->y + dst_rect->h), (sci_rect->y + sci_rect->h));
+
+	if (r < l || b < t)
+		*res_rect = (struct mdss_mdp_img_rect){0, 0, 0, 0};
+	else
+		*res_rect = (struct mdss_mdp_img_rect){l, t, (r-l), (b-t)};
+}
 int mdss_mdp_get_rau_strides(u32 w, u32 h,
 			       struct mdss_mdp_format_params *fmt,
 			       struct mdss_mdp_plane_sizes *ps)
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 72288c2..a9f3e35 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -675,7 +675,8 @@
 		break;
 	case MSMFB_WRITEBACK_QUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_queue(mfd, arg, false);
+			ret = mdss_mdp_wb_queue(mfd, &data, false);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb queue buf failed on copy_from_user\n");
 			ret = -EFAULT;
@@ -683,7 +684,8 @@
 		break;
 	case MSMFB_WRITEBACK_DEQUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_dequeue(mfd, arg);
+			ret = mdss_mdp_wb_dequeue(mfd, &data);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb dequeue buf failed on copy_from_user\n");
 			ret = -EFAULT;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d05ca66..75fc095 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -24,6 +24,7 @@
 };
 
 #define DEFAULT_FRAME_RATE	60
+#define MDSS_DSI_RST_SEQ_LEN	10
 
 /* panel type list */
 #define NO_PANEL		0xffff	/* No Panel */
@@ -84,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
  *
@@ -112,13 +118,15 @@
  *				display state from boot loader to panel driver.
  *				The event handler will enable the panel and
  *				vote for the display clocks.
+ * @MDSS_EVENT_PANEL_UPDATE_FPS: Event to update the frame rate of the panel.
  * @MDSS_EVENT_FB_REGISTERED:	Called after fb dev driver has been registered,
  *				panel driver gets ptr to struct fb_info which
  *				holds fb dev information.
  * @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,
@@ -132,9 +140,11 @@
 	MDSS_EVENT_CHECK_PARAMS,
 	MDSS_EVENT_CONT_SPLASH_BEGIN,
 	MDSS_EVENT_CONT_SPLASH_FINISH,
+	MDSS_EVENT_PANEL_UPDATE_FPS,
 	MDSS_EVENT_FB_REGISTERED,
 	MDSS_EVENT_PANEL_CLK_CTRL,
 	MDSS_EVENT_DSI_CMDLIST_KOFF,
+	MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
 };
 
 struct lcd_panel_info {
@@ -214,6 +224,11 @@
 	char hw_vsync_mode;
 };
 
+enum dynamic_fps_update {
+	DFPS_SUSPEND_RESUME_MODE,
+	DFPS_IMMEDIATE_CLK_UPDATE_MODE,
+};
+
 enum lvds_mode {
 	LVDS_SINGLE_CHANNEL_MODE,
 	LVDS_DUAL_CHANNEL_MODE,
@@ -263,14 +278,24 @@
 	u32 frame_count;
 	u32 is_3d_panel;
 	u32 out_format;
+	u32 rst_seq[MDSS_DSI_RST_SEQ_LEN];
+	u32 rst_seq_len;
 	u32 vic; /* video identification code */
+	u32 roi_x;
+	u32 roi_y;
+	u32 roi_w;
+	u32 roi_h;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int pwm_period;
 	u32 mode_gpio_state;
+	bool dynamic_fps;
+	char dfps_update;
+	int new_fps;
 
 	u32 cont_splash_enabled;
+	u32 partial_update_enabled;
 	struct ion_handle *splash_ihdl;
 	u32 panel_power_on;
 
@@ -354,6 +379,20 @@
 			pinfo->lcdc.v_pulse_width;
 }
 
+/*
+ * mdss_panel_get_htotal() - return panel horizontal width
+ * @pinfo:	Pointer to panel info containing all panel information
+ *
+ * Returns the total width of the panel including any blanking regions
+ * which are not visible to user but used for calculations.
+ */
+static inline int mdss_panel_get_htotal(struct mdss_panel_info *pinfo)
+{
+	return pinfo->xres + pinfo->lcdc.h_back_porch +
+			pinfo->lcdc.h_front_porch +
+			pinfo->lcdc.h_pulse_width;
+}
+
 int mdss_register_panel(struct platform_device *pdev,
 	struct mdss_panel_data *pdata);
 
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index d24daab..f7ea557 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -106,13 +106,64 @@
 #define PREF_DIV_RATIO 27
 struct dsiphy_pll_divider_config pll_divider_config;
 
-int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
-			    u32 *expected_dsi_pclk)
+int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
+			    int frame_rate)
 {
 	u32 fb_divider, rate, vco;
 	u32 div_ratio = 0;
 	u32 pll_analog_posDiv = 1;
+	u32 h_period, v_period;
+	u32 dsi_pclk_rate;
+	u8 lanes = 0, bpp;
 	struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
+
+	if (panel_info->mipi.data_lane3)
+		lanes += 1;
+	if (panel_info->mipi.data_lane2)
+		lanes += 1;
+	if (panel_info->mipi.data_lane1)
+		lanes += 1;
+	if (panel_info->mipi.data_lane0)
+		lanes += 1;
+
+	switch (panel_info->mipi.dst_format) {
+	case DSI_CMD_DST_FORMAT_RGB888:
+	case DSI_VIDEO_DST_FORMAT_RGB888:
+	case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE:
+		bpp = 3;
+		break;
+	case DSI_CMD_DST_FORMAT_RGB565:
+	case DSI_VIDEO_DST_FORMAT_RGB565:
+		bpp = 2;
+		break;
+	default:
+		bpp = 3;	/* Default format set to RGB888 */
+		break;
+	}
+
+	h_period = mdss_panel_get_htotal(panel_info);
+	v_period = mdss_panel_get_vtotal(panel_info);
+
+	if ((frame_rate !=
+	     panel_info->mipi.frame_rate) ||
+	    (!panel_info->clk_rate)) {
+		h_period += panel_info->lcdc.xres_pad;
+		v_period += panel_info->lcdc.yres_pad;
+
+		if (lanes > 0) {
+			panel_info->clk_rate =
+			((h_period * v_period *
+			  frame_rate * bpp * 8)
+			   / lanes);
+		} else {
+			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+			panel_info->clk_rate =
+				(h_period * v_period * frame_rate * bpp * 8);
+		}
+	}
+	pll_divider_config.clk_rate = panel_info->clk_rate;
+
+
 	if (pll_divider_config.clk_rate == 0)
 		pll_divider_config.clk_rate = 454000000;
 
@@ -176,9 +227,13 @@
 		dsi_pclk.n = mnd_entry->pclk_n;
 		dsi_pclk.d = mnd_entry->pclk_d;
 	}
-	*expected_dsi_pclk = (((pll_divider_config.clk_rate) * lanes)
+	dsi_pclk_rate = (((pll_divider_config.clk_rate) * lanes)
 				      / (8 * bpp));
 
+	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
+		dsi_pclk_rate = 35000000;
+	panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate;
+
 	return 0;
 }
 
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index 096f777..b017caa 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -25,6 +25,7 @@
 	ANDROID_ALARM_RTC,
 	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
 	ANDROID_ALARM_ELAPSED_REALTIME,
+	ANDROID_ALARM_RTC_POWEROFF_WAKEUP,
 	ANDROID_ALARM_SYSTEMTIME,
 
 	ANDROID_ALARM_TYPE_COUNT,
@@ -86,6 +87,7 @@
 				1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
 	ANDROID_ALARM_ELAPSED_REALTIME_MASK =
 				1U << ANDROID_ALARM_ELAPSED_REALTIME,
+	ANDROID_ALARM_RTC_POWEROFF_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_POWEROFF_WAKEUP,
 	ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
 	ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
 };
diff --git a/include/linux/bif/consumer.h b/include/linux/bif/consumer.h
index e4c190e..a4579db 100644
--- a/include/linux/bif/consumer.h
+++ b/include/linux/bif/consumer.h
@@ -311,10 +311,11 @@
  * @type:		Object type
  * @version:		Object version
  * @manufacturer_id:	Manufacturer ID number allocated by MIPI
- * @length:		Length of the entire object including header and CRC
+ * @length:		Length of the entire object including header and CRC;
+ *			data length == total length - 8.
  * @data:		Raw byte data found in the object
  * @crc:		CRC of the object calculated using CRC-CCITT
- * @list:		Linked-list connection parameter
+ * @list:		Linked-list connection parameter; internal use only
  * @addr:		BIF slave address correspond to the start of the object
  *
  * manufacturer_id == 0x0000 if MIPI type and version.
@@ -342,6 +343,8 @@
  *				is used to denote a 256 byte buffer.
  * @nvm_base_address:		BIF slave address where NVM begins
  * @nvm_size:			NVM size in bytes
+ * @nvm_lock_offset:		Offset from the beginning of NVM of the first
+ *				writable address
  * @object_count:		Number of BIF objects read from NVM
  * @object_list:		List of BIF objects read from NVM
  */
@@ -351,6 +354,7 @@
 	u8			write_buffer_size;
 	u16			nvm_base_address;
 	u16			nvm_size;
+	u16			nvm_lock_offset;
 	int			object_count;
 	struct list_head	object_list;
 };
@@ -412,6 +416,9 @@
 #define BIF_MATCH_FUNCTION_TYPE		BIT(2)
 #define BIF_MATCH_FUNCTION_VERSION	BIT(3)
 #define BIF_MATCH_IGNORE_PRESENCE	BIT(4)
+#define BIF_MATCH_OBJ_TYPE		BIT(5)
+#define BIF_MATCH_OBJ_VERSION		BIT(6)
+#define BIF_MATCH_OBJ_MANUFACTURER_ID	BIT(7)
 
 /**
  * struct bif_match_criteria - specifies the matching criteria that a BIF
@@ -428,6 +435,17 @@
  * @ignore_presence:	If true, then slaves that are currently not present
  *			will be successfully matched against.  By default, only
  *			present slaves can be matched.
+ * @obj_type:		Defines the type of a BIF object found in the
+ *			non-volatile memory of a slave.
+ * @obj_version:	Defines the version of a BIF object found in the
+ *			non-volatile memory of a slave.
+ * @obj_manufacturer_id: Manufacturer ID of a BIF object found in the
+ *			non-volatile memory of a slave.
+ *
+ * If function_type and function_verion are both specified, then they must both
+ * match for a single BIF function.  If obj_type and obj_version or
+ * obj_manufacturer_id are specified, then all must match for a single BIF
+ * object.
  */
 struct bif_match_criteria {
 	u32	match_mask;
@@ -436,6 +454,34 @@
 	u8	function_type;
 	u8	function_version;
 	bool	ignore_presence;
+	u8	obj_type;
+	u8	obj_version;
+	u16	obj_manufacturer_id;
+};
+
+/* Mask values to be ORed for use in bif_obj_match_criteria.match_mask. */
+#define BIF_OBJ_MATCH_TYPE		BIT(0)
+#define BIF_OBJ_MATCH_VERSION		BIT(1)
+#define BIF_OBJ_MATCH_MANUFACTURER_ID	BIT(2)
+
+/**
+ * struct bif_obj_match_criteria - specifies the matching criteria that a BIF
+ *			consumer uses to find an appropriate BIF data object
+ *			within a slave
+ * @match_mask:		Mask value specifying which parameters to match upon.
+ *			This value should be some ORed combination of
+ *			BIF_OBJ_MATCH_* specified above.
+ * @type:		Defines the type of the object.  The type may be either
+ *			MIPI or manufacturer defined.
+ * @version:		Defines the version of the object.  The version may be
+ *			either MIPI or manufacturer defined.
+ * @manufacturer_id:	Manufacturer ID number allocated by MIPI.
+ */
+struct bif_obj_match_criteria {
+	u32	match_mask;
+	u8	type;
+	u8	version;
+	u16	manufacturer_id;
 };
 
 /**
@@ -472,6 +518,8 @@
 			struct notifier_block *nb);
 
 int bif_trigger_task(struct bif_slave *slave, unsigned int task);
+int bif_enable_auto_task(struct bif_slave *slave, unsigned int task);
+int bif_disable_auto_task(struct bif_slave *slave, unsigned int task);
 int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
 
 int bif_ctrl_count(void);
@@ -481,10 +529,10 @@
 
 int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl);
 
-int bif_slave_match_count(const struct bif_ctrl *ctrl,
+int bif_slave_match_count(struct bif_ctrl *ctrl,
 			const struct bif_match_criteria *match_criteria);
 
-struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
 	unsigned int id, const struct bif_match_criteria *match_criteria);
 
 void bif_slave_put(struct bif_slave *slave);
@@ -500,9 +548,31 @@
 int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
 				u16 *function_pointer);
 
+int bif_object_match_count(struct bif_slave *slave,
+			const struct bif_obj_match_criteria *match_criteria);
+
+struct bif_object *bif_object_match_get(struct bif_slave *slave,
+	unsigned int id, const struct bif_obj_match_criteria *match_criteria);
+
+void bif_object_put(struct bif_object *object);
+
 int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len);
 int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
 
+int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
+				int len);
+int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
+				int len);
+
+int bif_object_write(struct bif_slave *slave, u8 type, u8 version, u16
+			manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_overwrite(struct bif_slave *slave,
+	struct bif_object *object, u8 type, u8 version,
+	u16 manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_delete(struct bif_slave *slave, const struct bif_object *object);
+
 int bif_slave_is_present(struct bif_slave *slave);
 
 int bif_slave_is_selected(struct bif_slave *slave);
@@ -534,6 +604,12 @@
 
 static inline int bif_trigger_task(struct bif_slave *slave, unsigned int task)
 { return -EPERM; }
+static inline int bif_enable_auto_task(struct bif_slave *slave,
+			unsigned int task)
+{ return -EPERM; }
+static inline int bif_disable_auto_task(struct bif_slave *slave,
+			unsigned int task)
+{ return -EPERM; }
 static inline int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
 { return -EPERM; }
 
@@ -544,13 +620,14 @@
 { return ERR_PTR(-EPERM); }
 static inline void bif_ctrl_put(struct bif_ctrl *ctrl) { return; }
 
-int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl) { return -EPERM; }
+static inline int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl)
+{ return -EPERM; }
 
-static inline int bif_slave_match_count(const struct bif_ctrl *ctrl,
+static inline int bif_slave_match_count(struct bif_ctrl *ctrl,
 			const struct bif_match_criteria *match_criteria)
 { return -EPERM; }
 
-static inline struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+static inline struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
 	unsigned int id, const struct bif_match_criteria *match_criteria)
 { return ERR_PTR(-EPERM); }
 
@@ -571,6 +648,17 @@
 				u8 *version, u16 *function_pointer)
 { return -EPERM; }
 
+static inline int bif_object_match_count(struct bif_slave *slave,
+			const struct bif_obj_match_criteria *match_criteria)
+{ return -EPERM; }
+
+static inline struct bif_object *bif_object_match_get(struct bif_slave *slave,
+	unsigned int id, const struct bif_obj_match_criteria *match_criteria)
+{ return ERR_PTR(-EPERM); }
+
+static inline void bif_object_put(struct bif_object *object)
+{}
+
 static inline int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf,
 				int len)
 { return -EPERM; }
@@ -578,18 +666,42 @@
 				int len)
 { return -EPERM; }
 
-int bif_slave_is_present(struct bif_slave *slave) { return -EPERM; }
-
-int bif_slave_is_selected(struct bif_slave *slave) { return -EPERM; }
-int bif_slave_select(struct bif_slave *slave) { return -EPERM; }
-
-int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
+static inline int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset,
+				u8 *buf, int len)
 { return -EPERM; }
-int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
-					u8 data, int *response)
+static inline int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset,
+				u8 *buf, int len)
 { return -EPERM; }
-int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
-		u8 data, bool *query_response)
+
+static inline int bif_object_write(struct bif_slave *slave, u8 type, u8 version,
+			u16 manufacturer_id, const u8 *data, int data_len)
+{ return -EPERM; }
+
+static inline int bif_object_overwrite(struct bif_slave *slave,
+	struct bif_object *object, u8 type, u8 version,
+	u16 manufacturer_id, const u8 *data, int data_len)
+{ return -EPERM; }
+
+static inline int bif_object_delete(struct bif_slave *slave,
+		const struct bif_object *object)
+{ return -EPERM; }
+
+static inline int bif_slave_is_present(struct bif_slave *slave)
+{ return -EPERM; }
+
+static inline int bif_slave_is_selected(struct bif_slave *slave)
+{ return -EPERM; }
+static inline int bif_slave_select(struct bif_slave *slave)
+{ return -EPERM; }
+
+static inline int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl,
+				int transaction, u8 data)
+{ return -EPERM; }
+static inline int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl,
+				int transaction, u8 data, int *response)
+{ return -EPERM; }
+static inline int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl,
+				int transaction, u8 data, bool *query_response)
 { return -EPERM; }
 
 static inline void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
@@ -601,11 +713,14 @@
 { return 0; }
 
 static inline int bif_ctrl_measure_rid(struct bif_ctrl *ctrl) { return -EPERM; }
-int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl) { return -EPERM; }
-int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+static inline int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl)
 { return -EPERM; }
-int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl) { return -EPERM; }
-int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
+static inline int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+{ return -EPERM; }
+static inline int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl)
+{ return -EPERM; }
+static inline int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl,
+				enum bif_bus_state state)
 { return -EPERM; }
 
 #endif
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index fbe89e1..eba0157 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -206,6 +206,7 @@
 #define CLOCK_SOURCE_WATCHDOG			0x10
 #define CLOCK_SOURCE_VALID_FOR_HRES		0x20
 #define CLOCK_SOURCE_UNSTABLE			0x40
+#define CLOCK_SOURCE_SUSPEND_NONSTOP		0x80
 
 /* simplify initialization of mask field */
 #define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1)
diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h
index 149133e..7b84534 100644
--- a/include/linux/input/ft5x06_ts.h
+++ b/include/linux/input/ft5x06_ts.h
@@ -58,6 +58,7 @@
 	bool fw_vkey_support;
 	bool no_force_update;
 	bool i2c_pull_up;
+	bool ignore_id_check;
 	int (*power_init) (bool);
 	int (*power_on) (bool);
 };
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 5df022e..6716ce3 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -43,6 +43,15 @@
  * @reset_gpio: reset gpio
  * @panel_x: panel maximum values on the x
  * @panel_y: panel maximum values on the y
+ * @disp_maxx: display panel maximum values on the x
+ * @disp_maxy: display panel maximum values on the y
+ * @disp_minx: display panel minimum values on the x
+ * @disp_miny: display panel minimum values on the y
+ * @panel_maxx: touch panel maximum values on the x
+ * @panel_maxy: touch panel maximum values on the y
+ * @panel_minx: touch panel minimum values on the x
+ * @panel_miny: touch panel minimum values on the y
+ * @reset_delay: reset delay
  * @gpio_config: pointer to gpio configuration function
  * @capacitance_button_map: pointer to 0d button map
  */
@@ -52,12 +61,20 @@
 	bool i2c_pull_up;
 	bool power_down_enable;
 	bool disable_gpios;
+	bool do_lockdown;
 	unsigned irq_gpio;
 	u32 irq_flags;
 	u32 reset_flags;
 	unsigned reset_gpio;
-	unsigned panel_x;
-	unsigned panel_y;
+	unsigned panel_minx;
+	unsigned panel_miny;
+	unsigned panel_maxx;
+	unsigned panel_maxy;
+	unsigned disp_minx;
+	unsigned disp_miny;
+	unsigned disp_maxx;
+	unsigned disp_maxy;
+	unsigned reset_delay;
 	const char *fw_image_name;
 	int (*gpio_config)(unsigned gpio, bool configure);
 	struct synaptics_rmi4_capacitance_button_map *capacitance_button_map;
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/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index b7ba6fb..ffbd732 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -69,20 +69,20 @@
 #define TABLA_DCYCLE_3839 0xE
 #define TABLA_DCYCLE_4095 0xF
 
-#define TAIKO_MCLK_CLK_12P288MHZ 12288000
-#define TAIKO_MCLK_CLK_9P6HZ 9600000
+#define WCD9XXX_MCLK_CLK_12P288MHZ 12288000
+#define WCD9XXX_MCLK_CLK_9P6HZ 9600000
 
 /* Only valid for 9.6 MHz mclk */
-#define TAIKO_DMIC_SAMPLE_RATE_2P4MHZ 2400000
-#define TAIKO_DMIC_SAMPLE_RATE_3P2MHZ 3200000
-#define TAIKO_DMIC_SAMPLE_RATE_4P8MHZ 4800000
+#define WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ 2400000
+#define WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ 3200000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ 4800000
 
 /* Only valid for 12.288 MHz mclk */
-#define TAIKO_DMIC_SAMPLE_RATE_3P072MHZ 3072000
-#define TAIKO_DMIC_SAMPLE_RATE_4P096MHZ 4096000
-#define TAIKO_DMIC_SAMPLE_RATE_6P144MHZ 6144000
+#define WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ 3072000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ 4096000
+#define WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ 6144000
 
-#define TAIKO_DMIC_SAMPLE_RATE_UNDEFINED 0
+#define WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED 0
 
 struct wcd9xxx_amic {
 	/*legacy mode, txfe_enable and txfe_buff take 7 input
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 48268f0..a5fa304 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -302,16 +302,16 @@
  * On nommu, vmalloc/vfree wrap through kmalloc/kfree directly, so there
  * is no special casing required.
  */
+
+#ifdef CONFIG_MMU
+extern int is_vmalloc_addr(const void *x);
+#else
 static inline int is_vmalloc_addr(const void *x)
 {
-#ifdef CONFIG_MMU
-	unsigned long addr = (unsigned long)x;
-
-	return addr >= VMALLOC_START && addr < VMALLOC_END;
-#else
 	return 0;
-#endif
 }
+#endif
+
 #ifdef CONFIG_MMU
 extern int is_vmalloc_or_module_addr(const void *x);
 #else
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9d15908..d0ad3e4 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -391,6 +391,7 @@
 	unsigned int		idle_timeout;
 	struct notifier_block        reboot_notify;
 	bool issue_long_pon;
+	u8 cached_ext_csd;
 };
 
 /*
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index e8ca1cd..853899e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -63,6 +63,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
 #define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE	_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
+#define AUDIO_SET_HW_DELAY_RX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay)
+#define AUDIO_SET_HW_DELAY_TX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay)
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+40)
 
 /* ACDB structures */
@@ -96,6 +100,11 @@
 	int status;
 };
 
+struct hw_delay {
+	uint32_t num_entries;
+	void *delay_info;
+};
+
 /* For Real-Time Audio Calibration */
 #define AUDIO_GET_RTAC_ADM_INFO		_IOR(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index baa9d6c..0c08421 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -187,6 +187,7 @@
 #define MDP_BACKEND_COMPOSITION		0x00040000
 #define MDP_BORDERFILL_SUPPORTED	0x00010000
 #define MDP_SECURE_OVERLAY_SESSION      0x00008000
+#define MDP_SECURE_DISPLAY_OVERLAY_SESSION	0x00002000
 #define MDP_OV_PIPE_FORCE_DMA		0x00004000
 #define MDP_MEMORY_ID_TYPE_FB		0x00001000
 #define MDP_BWC_EN			0x00000400
@@ -838,6 +839,7 @@
 struct mdp_buf_sync {
 	uint32_t flags;
 	uint32_t acq_fen_fd_cnt;
+	uint32_t session_id;
 	int *acq_fen_fd;
 	int *rel_fen_fd;
 };
@@ -862,6 +864,7 @@
 	uint32_t wait_for_finish;
 	struct fb_var_screeninfo var;
 	struct mdp_buf_fence buf_fence;
+	struct mdp_rect roi;
 };
 
 struct mdp_page_protection {
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 5106c71..93af04d 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -103,6 +103,7 @@
 	POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_CURRENT_AVG,
 	POWER_SUPPLY_PROP_POWER_NOW,
@@ -228,6 +229,7 @@
 extern int power_supply_set_battery_charged(struct power_supply *psy);
 extern int power_supply_set_current_limit(struct power_supply *psy, int limit);
 extern int power_supply_set_online(struct power_supply *psy, bool enable);
+extern int power_supply_set_health_state(struct power_supply *psy, int health);
 extern int power_supply_set_present(struct power_supply *psy, bool enable);
 extern int power_supply_set_scope(struct power_supply *psy, int scope);
 extern int power_supply_set_charge_type(struct power_supply *psy, int type);
@@ -252,6 +254,9 @@
 static inline int power_supply_set_online(struct power_supply *psy,
 							bool enable)
 							{ return -ENOSYS; }
+static inline int power_supply_set_health_state(struct power_supply *psy,
+							int health)
+							{ return -ENOSYS; }
 static inline int power_supply_set_present(struct power_supply *psy,
 							bool enable)
 							{ return -ENOSYS; }
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 13bef66..6e711c2 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -615,6 +615,21 @@
 	QPNP_ADC_TM_CH_SELECT_NONE
 };
 
+/**
+ * Channel index for the corresponding index to qpnp_adc_tm_channel_selec
+ */
+enum qpnp_adc_tm_channel_num {
+	QPNP_ADC_TM_CHAN0 = 0,
+	QPNP_ADC_TM_CHAN1,
+	QPNP_ADC_TM_CHAN2,
+	QPNP_ADC_TM_CHAN3,
+	QPNP_ADC_TM_CHAN4,
+	QPNP_ADC_TM_CHAN5,
+	QPNP_ADC_TM_CHAN6,
+	QPNP_ADC_TM_CHAN7,
+	QPNP_ADC_TM_CHAN_NONE
+};
+
 enum qpnp_comp_scheme_type {
 	COMP_ID_GF = 0,
 	COMP_ID_SMIC,
diff --git a/include/linux/security.h b/include/linux/security.h
index 673afbb..b62f396 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1381,6 +1381,11 @@
 struct security_operations {
 	char name[SECURITY_NAME_MAX + 1];
 
+	int (*binder_set_context_mgr) (struct task_struct *mgr);
+	int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
+
 	int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
 	int (*ptrace_traceme) (struct task_struct *parent);
 	int (*capget) (struct task_struct *target,
@@ -1664,6 +1669,10 @@
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1842,6 +1851,26 @@
 	return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
 					     unsigned int mode)
 {
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 84c59dc..d950b5c 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -154,6 +154,7 @@
 	KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
 	KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
 	KERN_BOOT_REASON = 77, /* int: identify reason system was booted */
+	KERN_COLD_BOOT = 78, /* int: identify if system cold booted */
 };
 
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 1bb3b06..ed6d41b 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -98,7 +98,7 @@
 #define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
 
 struct sensor_threshold {
-	int temp;
+	long temp;
 	enum thermal_trip_type trip;
 	int (*notify)(enum thermal_trip_type type, int temp, void *data);
 	void *data;
@@ -108,8 +108,8 @@
 struct sensor_info {
 	uint32_t sensor_id;
 	struct thermal_zone_device *tz;
-	int threshold_min;
-	int threshold_max;
+	long threshold_min;
+	long threshold_max;
 	int max_idx;
 	int min_idx;
 	struct list_head sensor_list;
@@ -190,7 +190,7 @@
 int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
 int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
 int thermal_sensor_trip(struct thermal_zone_device *tz,
-		enum thermal_trip_type trip, unsigned long temp);
+		enum thermal_trip_type trip, long temp);
 
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index f462b64..be92ca7 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -440,6 +440,7 @@
 	unsigned int host_mode;
 	unsigned int voltage_max;
 	unsigned int current_max;
+	unsigned int usbin_health;
 
 	dev_t ext_chg_dev;
 	struct cdev ext_chg_cdev;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c9be394..af206c7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -706,6 +706,8 @@
 #define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
 #define V4L2_QCOM_BUF_DROP_FRAME 0x100000
 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
+#define V4L2_QCOM_BUF_FLAG_EOS          0x2000
+#define V4L2_QCOM_BUF_FLAG_READONLY     0x400000
 
 /*
  *	O V E R L A Y   P R E V I E W
@@ -1862,22 +1864,25 @@
 	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
 };
 
-#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE		\
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT	\
 		(V4L2_CID_MPEG_MSM_VIDC_BASE+30)
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT	\
+		 (V4L2_CID_MPEG_MSM_VIDC_BASE+31)
 enum v4l2_mpeg_vidc_video_alloc_mode_type {
 	V4L2_MPEG_VIDC_VIDEO_STATIC	= 0,
 	V4L2_MPEG_VIDC_VIDEO_RING	= 1,
+	V4L2_MPEG_VIDC_VIDEO_DYNAMIC	= 2,
 };
 
 #define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY	\
-		(V4L2_CID_MPEG_MSM_VIDC_BASE+31)
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+32)
 enum v4l2_mpeg_vidc_video_assembly {
 	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE	= 0,
 	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE	= 1,
 };
 
 #define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
-		(V4L2_CID_MPEG_MSM_VIDC_BASE+32)
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+33)
 enum v4l2_mpeg_vidc_video_vp8_profile_level {
 	V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
 	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
@@ -2447,7 +2452,10 @@
 		(V4L2_EVENT_MSM_VIDC_START + 3)
 #define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	(V4L2_EVENT_MSM_VIDC_START + 4)
 #define V4L2_EVENT_MSM_VIDC_SYS_ERROR	(V4L2_EVENT_MSM_VIDC_START + 5)
-
+#define V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE \
+		(V4L2_EVENT_MSM_VIDC_START + 6)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \
+		(V4L2_EVENT_MSM_VIDC_START + 7)
 
 /* Payload for V4L2_EVENT_VSYNC */
 struct v4l2_event_vsync {
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 6071e91..7675a5c 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -14,6 +14,7 @@
 #define VM_USERMAP	0x00000008	/* suitable for remap_vmalloc_range */
 #define VM_VPAGES	0x00000010	/* buffer for pages was vmalloc'ed */
 #define VM_UNLIST	0x00000020	/* vm_struct is not listed in vmlist */
+#define VM_LOWMEM	0x00000040	/* Tracking of direct mapped lowmem */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
@@ -134,6 +135,7 @@
 extern struct vm_struct *vmlist;
 extern __init void vm_area_add_early(struct vm_struct *vm);
 extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
+extern __init int vm_area_check_early(struct vm_struct *vm);
 
 #ifdef CONFIG_SMP
 # ifdef CONFIG_MMU
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 540fd2c..326e8bf 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -231,6 +231,7 @@
 struct msm_camera_i2c_reg_array {
 	uint16_t reg_addr;
 	uint16_t reg_data;
+	uint32_t delay;
 };
 
 struct msm_camera_i2c_reg_setting {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 2164275..868be9f 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -28,7 +28,7 @@
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
-int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buffers(void *instance, int buffer_type);
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 23b19b5..7b0ad14 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -129,6 +129,7 @@
 struct msm_vfe_axi_stream_request_cmd {
 	uint32_t session_id;
 	uint32_t stream_id;
+	uint32_t vt_enable;
 	uint32_t output_format;/*Planar/RAW/Misc*/
 	enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/
 	struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
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/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index fb58d12..bbda72e 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1968,6 +1968,14 @@
 	 */
 } __packed;
 
+#define AFE_PARAM_ID_DEVICE_HW_DELAY     0x00010243
+#define AFE_API_VERSION_DEVICE_HW_DELAY  0x1
+
+struct afe_param_id_device_hw_delay_cfg {
+	uint32_t    device_hw_delay_minor_version;
+	uint32_t    delay_in_us;
+} __packed;
+
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -1976,6 +1984,7 @@
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
 	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
 	struct afe_param_id_pseudo_port_cfg       pseudo_port;
+	struct afe_param_id_device_hw_delay_cfg   hw_delay;
 } __packed;
 
 struct afe_audioif_config_command_no_payload {
@@ -2481,6 +2490,8 @@
 
 #define ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT 0x00010BE4
 
+#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
+
 #define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
 
 #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
@@ -4298,7 +4309,6 @@
 struct asm_aac_dual_mono_mapping_param {
 	struct apr_hdr							hdr;
 	struct asm_stream_cmd_set_encdec_param	encdec;
-	struct asm_enc_cfg_blk_param_v2			encblk;
 	u16    left_channel_sce;
 	u16    right_channel_sce;
 
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/smp.c b/kernel/smp.c
index 2f8b10e..3cbd828 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -310,20 +310,20 @@
 	 */
 	this_cpu = get_cpu();
 
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
-		     && !oops_in_progress);
-
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		func(info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+			     && !oops_in_progress);
+
 		if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
 			struct call_single_data *data = &d;
 
@@ -408,20 +408,21 @@
 	unsigned long flags;
 
 	this_cpu = get_cpu();
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
-		     && !oops_in_progress);
 
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		data->func(data->info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait
+			     && irqs_disabled() && !oops_in_progress);
+
 		csd_lock(data);
 		generic_exec_single(cpu, data, wait);
 	}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b390dad..d16a59ec 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1009,7 +1009,15 @@
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
 		.proc_handler	= proc_dointvec,
-},
+	},
+
+	{
+		.procname	= "cold_boot",
+		.data		= &cold_boot,
+		.maxlen		= sizeof(int),
+		.mode		= 0444,
+		.proc_handler	= proc_dointvec,
+	},
 #endif
 /*
  * NOTE: do not add new entries to this table unless you have read
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index acb60be..6170f45 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -138,6 +138,7 @@
 	{ CTL_INT,	KERN_MAX_LOCK_DEPTH,		"max_lock_depth" },
 	{ CTL_INT,	KERN_PANIC_ON_NMI,		"panic_on_unrecovered_nmi" },
 	{ CTL_INT,	KERN_BOOT_REASON,		"boot_reason" },
+	{ CTL_INT,	KERN_COLD_BOOT,			"cold_boot" },
 	{}
 };
 
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index df30ee0..818920f 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -127,7 +127,7 @@
 /* Commands for resetting the watchdog */
 static void __touch_watchdog(void)
 {
-	int this_cpu = smp_processor_id();
+	int this_cpu = raw_smp_processor_id();
 
 	__this_cpu_write(watchdog_touch_ts, get_timestamp(this_cpu));
 }
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 0131170..3db5820 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -154,7 +154,7 @@
  * down, but we are still initializing the system.  Pages are given directly
  * to the page allocator, no bootmem metadata is updated because it is gone.
  */
-void __init free_bootmem_late(unsigned long addr, unsigned long size)
+void free_bootmem_late(unsigned long addr, unsigned long size)
 {
 	unsigned long cursor, end;
 
diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c
index 789ff70..bc91cba 100644
--- a/mm/debug-pagealloc.c
+++ b/mm/debug-pagealloc.c
@@ -69,6 +69,7 @@
 
 	print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
 			end - start + 1, 1);
+	BUG_ON(PANIC_CORRUPTION);
 	dump_stack();
 }
 
diff --git a/mm/memory.c b/mm/memory.c
index b6ab040..acc9aa6 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -58,6 +58,7 @@
 #include <linux/swapops.h>
 #include <linux/elf.h>
 #include <linux/gfp.h>
+#include <linux/bug.h>
 
 #include <asm/io.h>
 #include <asm/pgalloc.h>
@@ -705,6 +706,9 @@
 	if (vma->vm_file && vma->vm_file->f_op)
 		print_symbol(KERN_ALERT "vma->vm_file->f_op->mmap: %s\n",
 				(unsigned long)vma->vm_file->f_op->mmap);
+
+	BUG_ON(PANIC_CORRUPTION);
+
 	dump_stack();
 	add_taint(TAINT_BAD_PAGE);
 }
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9cc2f45..46ccd2f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -745,7 +745,7 @@
 	local_irq_restore(flags);
 }
 
-void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
+void __free_pages_bootmem(struct page *page, unsigned int order)
 {
 	unsigned int nr_pages = 1 << order;
 	unsigned int loop;
diff --git a/mm/slub.c b/mm/slub.c
index 80848cd..931c8eb 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2310,13 +2310,18 @@
 		return NULL;
 
 redo:
-
 	/*
 	 * Must read kmem_cache cpu data via this cpu ptr. Preemption is
 	 * enabled. We may switch back and forth between cpus while
 	 * reading from one cpu area. That does not matter as long
 	 * as we end up on the original cpu again when doing the cmpxchg.
+	 *
+	 * Preemption is disabled for the retrieval of the tid because that
+	 * must occur from the current processor. We cannot allow rescheduling
+	 * on a different processor between the determination of the pointer
+	 * and the retrieval of the tid.
 	 */
+	preempt_disable();
 	c = __this_cpu_ptr(s->cpu_slab);
 
 	/*
@@ -2326,7 +2331,7 @@
 	 * linked list in between.
 	 */
 	tid = c->tid;
-	barrier();
+	preempt_enable();
 
 	object = c->freelist;
 	if (unlikely(!object || !node_match(c, node)))
@@ -2572,10 +2577,11 @@
 	 * data is retrieved via this pointer. If we are on the same cpu
 	 * during the cmpxchg then the free will succedd.
 	 */
+	preempt_disable();
 	c = __this_cpu_ptr(s->cpu_slab);
 
 	tid = c->tid;
-	barrier();
+	preempt_enable();
 
 	if (likely(page == c->page)) {
 		set_freepointer(s, object, c->freelist);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 5065adb..e174693 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,6 +184,36 @@
 	return ret;
 }
 
+#ifdef ENABLE_VMALLOC_SAVING
+int is_vmalloc_addr(const void *x)
+{
+	struct rb_node *n;
+	struct vmap_area *va;
+	int ret = 0;
+
+	spin_lock(&vmap_area_lock);
+
+	for (n = rb_first(vmap_area_root); n; rb_next(n)) {
+		va = rb_entry(n, struct vmap_area, rb_node);
+		if (x >= va->va_start && x < va->va_end) {
+			ret = 1;
+			break;
+		}
+	}
+
+	spin_unlock(&vmap_area_lock);
+	return ret;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+	unsigned long addr = (unsigned long)x;
+
+	return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
 int is_vmalloc_or_module_addr(const void *x)
 {
 	/*
@@ -1116,7 +1146,31 @@
 	return mem;
 }
 EXPORT_SYMBOL(vm_map_ram);
+/**
+ * vm_area_check_early - check if vmap area is already mapped
+ * @vm: vm_struct to be checked
+ *
+ * This function is used to check if the vmap area has been
+ * mapped already. @vm->addr, @vm->size and @vm->flags should
+ * contain proper values.
+ *
+ */
+int __init vm_area_check_early(struct vm_struct *vm)
+{
+	struct vm_struct *tmp, **p;
 
+	BUG_ON(vmap_initialized);
+	for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+		if (tmp->addr >= vm->addr) {
+			if (tmp->addr < vm->addr + vm->size)
+				return 1;
+		} else {
+			if (tmp->addr + tmp->size > vm->addr)
+				return 1;
+		}
+	}
+	return 0;
+}
 /**
  * vm_area_add_early - add vmap area early during boot
  * @vm: vm_struct to add
@@ -1392,15 +1446,26 @@
  */
 struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 {
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#else
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
+
 }
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 				const void *caller)
 {
-	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
 						-1, GFP_KERNEL, caller);
+#else
+	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
 }
 
 /**
@@ -2608,6 +2673,9 @@
 	if (v->flags & VM_VPAGES)
 		seq_printf(m, " vpages");
 
+	if (v->flags & VM_LOWMEM)
+		seq_printf(m, " lowmem");
+
 	show_numa_info(m, v);
 	seq_putc(m, '\n');
 	return 0;
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 5016fa5..c2b18e6 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -1014,7 +1014,7 @@
 	caif_assert(sk_unhashed(sk));
 	caif_assert(!sk->sk_socket);
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		pr_debug("Attempt to release alive CAIF socket: %p\n", sk);
+		WARN(1, "Attempt to release alive CAIF socket: %p\n", sk);
 		return;
 	}
 	sk_stream_kill_queues(&cf_sk->sk);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0b71165..f20b5cc 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -154,12 +154,12 @@
 	sk_mem_reclaim(sk);
 
 	if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
-		pr_err("Attempt to release TCP socket in state %d %p\n",
+		WARN(1, "Attempt to release TCP socket in state %d %p\n",
 		       sk->sk_state, sk);
 		return;
 	}
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		pr_err("Attempt to release alive inet socket %p\n", sk);
+		WARN(1, "Attempt to release alive inet socket %p\n", sk);
 		return;
 	}
 
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 07d7d55..433f7f7 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -408,7 +408,7 @@
 	sk_mem_reclaim(sk);
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		pr_err("Attempt to release alive iucv socket %p\n", sk);
+		WARN(1, "Attempt to release alive iucv socket %p\n", sk);
 		return;
 	}
 
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 7e5d927..153fbf1 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -99,7 +99,7 @@
 	skb_queue_purge(&sk->sk_receive_queue);
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		pr_err("Attempt to release alive pfkey socket: %p\n", sk);
+		WARN(1, "Attempt to release alive pfkey socket: %p\n", sk);
 		return;
 	}
 
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4f2c0df..a72cd66 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1168,7 +1168,7 @@
 	WARN_ON(atomic_read(&sk->sk_wmem_alloc));
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		pr_err("Attempt to release alive packet socket: %p\n", sk);
+		WARN(1, "Attempt to release alive packet socket: %p\n", sk);
 		return;
 	}
 
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 74c064c..798ea39 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -670,7 +670,7 @@
 	WARN_ON(sk->sk_socket);
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		printk("Attempt to release alive rxrpc socket: %p\n", sk);
+		WARN(1, "Attempt to release alive rxrpc socket: %p\n", sk);
 		return;
 	}
 }
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 109e30b..2a89d01 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -357,7 +357,7 @@
 	WARN_ON(!sk_unhashed(sk));
 	WARN_ON(sk->sk_socket);
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		printk(KERN_INFO "Attempt to release alive unix socket: %p\n", sk);
+		WARN(1, "Attempt to release alive unix socket: %p\n", sk);
 		return;
 	}
 
diff --git a/security/capability.c b/security/capability.c
index 5bb21b1..fc991bc 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -12,6 +12,26 @@
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static int cap_syslog(int type)
 {
 	return 0;
@@ -877,6 +897,10 @@
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+	set_to_cap_if_null(ops, binder_set_context_mgr);
+	set_to_cap_if_null(ops, binder_transaction);
+	set_to_cap_if_null(ops, binder_transfer_binder);
+	set_to_cap_if_null(ops, binder_transfer_file);
 	set_to_cap_if_null(ops, ptrace_access_check);
 	set_to_cap_if_null(ops, ptrace_traceme);
 	set_to_cap_if_null(ops, capget);
diff --git a/security/security.c b/security/security.c
index bf619ff..cecd55e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -130,6 +130,26 @@
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 	return security_ops->ptrace_access_check(child, mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d85b793..b28b7eb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1818,6 +1818,67 @@
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+	u32 mysid = current_sid();
+	u32 mgrsid = task_sid(mgr);
+
+	return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	u32 mysid = current_sid();
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	int rc;
+
+	if (mysid != fromsid) {
+		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
+		if (rc)
+			return rc;
+	}
+
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	u32 sid = task_sid(to);
+	struct file_security_struct *fsec = file->f_security;
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct inode_security_struct *isec = inode->i_security;
+	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	int rc;
+
+	COMMON_AUDIT_DATA_INIT(&ad, PATH);
+	ad.u.path = file->f_path;
+	ad.selinux_audit_data = &sad;
+
+	if (sid != fsec->sid) {
+		rc = avc_has_perm(sid, fsec->sid,
+				  SECCLASS_FD,
+				  FD__USE,
+				  &ad);
+		if (rc)
+			return rc;
+	}
+
+	if (unlikely(IS_PRIVATE(inode)))
+		return 0;
+
+	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+			    &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
 				     unsigned int mode)
 {
@@ -5523,6 +5584,11 @@
 static struct security_operations selinux_ops = {
 	.name =				"selinux",
 
+	.binder_set_context_mgr =	selinux_binder_set_context_mgr,
+	.binder_transaction =		selinux_binder_transaction,
+	.binder_transfer_binder =	selinux_binder_transfer_binder,
+	.binder_transfer_file =		selinux_binder_transfer_file,
+
 	.ptrace_access_check =		selinux_ptrace_access_check,
 	.ptrace_traceme =		selinux_ptrace_traceme,
 	.capget =			selinux_capget,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b8c5372..4a4a9ae 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -149,5 +149,6 @@
 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
 	{ "tun_socket",
 	  { COMMON_SOCK_PERMS, NULL } },
+	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
 	{ 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/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index fb115e7..942d095 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1136,9 +1136,6 @@
 			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
 			  -84,	40, digital_gain),
 
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch",
-		   MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
-
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 
@@ -1431,13 +1428,8 @@
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 				    0x20, 0x20);
-	} else {
+	} else
 		wcd8x10->adc_count--;
-		if (!wcd8x10->adc_count)
-			snd_soc_update_bits(codec,
-					    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
-					    0x20, 0x0);
-	}
 }
 
 static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
@@ -1577,15 +1569,20 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 	u16 micb_int_reg;
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 	char *internal3_text = "Internal3";
+	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	switch (w->reg) {
 	case MSM8X10_WCD_A_MICB_1_CTL:
 		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
+		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
+		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
+		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
 		break;
 	default:
 		dev_err(codec->dev,
@@ -1596,17 +1593,28 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		/* Let MBHC module know micbias is about to turn ON */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
 		else if (strnstr(w->name, internal2_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+
+		/* Always pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
+		/* Let MBHC module know so micbias is on */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		/* Let MBHC module know so micbias switch to be off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
 		else if (strnstr(w->name, internal2_text, 30))
@@ -1614,6 +1622,8 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
+		/* Disable pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
 		break;
 	}
 	return 0;
@@ -2414,6 +2424,11 @@
 		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
 		msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
+		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
+		msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2429,9 +2444,6 @@
 	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
 		&tx_adc2_mux),
 
-	SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
-			     7, 0),
-
 	SND_SOC_DAPM_INPUT("AMIC3"),
 
 	SND_SOC_DAPM_MUX_E("DEC1 MUX",
@@ -2507,8 +2519,10 @@
 	/* 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),
+	/* Keep the same default gain settings for TX paths */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_3_EN, 0x30),
 
 	/* ClassG fine tuning setting for 16 ohm HPH */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
@@ -2598,12 +2612,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)
 {
@@ -2628,14 +2636,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;
@@ -2647,16 +2647,60 @@
 	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
 }
 
+static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
+			    0x80, on ? 0x80 : 0x00);
+}
+
+static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+	bool turn_on)
+{
+	int ret = 0;
+
+	if (turn_on)
+		ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+	else
+		ret = snd_soc_dapm_disable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+
+	snd_soc_dapm_sync(&codec->dapm);
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			 __func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
+			    0x1C, on ? 0x14 : 0x00);
+}
+
+static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
+			    0x40, on ? 0x40 : 0x00);
+}
+
 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,
 };
 
 static void delayed_hs_detect_fn(struct work_struct *work)
@@ -2759,6 +2803,17 @@
 	.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_codec_probe(struct snd_soc_codec *codec)
 {
@@ -2766,6 +2821,7 @@
 	struct msm8x10_wcd *msm8x10_wcd;
 	struct wcd9xxx_core_resource *core_res;
 	int i, ret = 0;
+	struct msm8x10_wcd_pdata *pdata;
 
 	dev_dbg(codec->dev, "%s()\n", __func__);
 
@@ -2811,6 +2867,17 @@
 	msm8x10_wcd_bringup(codec);
 	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,
@@ -2824,7 +2891,7 @@
 
 	ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
 				&msm8x10_wcd_priv->resmgr,
-				codec, NULL, &mbhc_cb,
+				codec, NULL, &mbhc_cb, &cdc_intr_ids,
 				HELICON_MCLK_CLK_9P6MHZ, false);
 	if (ret) {
 		pr_err("%s: Failed to initialize mbhc\n", __func__);
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 4e07d7f..4857593 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,
@@ -1063,6 +1061,25 @@
 static const struct snd_kcontrol_new class_h_dsm_mux =
 	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
 
+static int tapan_hph_impedance_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	uint32_t zl, zr;
+	bool hphr;
+	struct soc_multi_mixer_control *mc;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+
+	hphr = mc->shift;
+	wcd9xxx_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
+	pr_debug("%s: zl %u, zr %u\n", __func__, zl, zr);
+	ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+	return 0;
+}
+
 static const struct snd_kcontrol_new tapan_common_snd_controls[] = {
 
 	SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
@@ -1165,6 +1182,11 @@
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
 	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
+
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+		       tapan_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+		       tapan_hph_impedance_get, NULL),
 };
 
 static const struct snd_kcontrol_new tapan_9306_snd_controls[] = {
@@ -4576,6 +4598,9 @@
 	u8 flag = pdata->amic_settings.use_pdata;
 	u8 i = 0, j = 0;
 	u8 val_txfe = 0, value = 0;
+	u8 dmic_sample_rate_value = 0;
+	u8 dmic_b1_ctl_value = 0;
+	u8 anc_ctl_value = 0;
 
 	if (!pdata) {
 		dev_err(codec->dev, "%s: NULL pdata\n", __func__);
@@ -4669,6 +4694,78 @@
 		 0x00 : 0x10);
 	snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
 
+	/* Set the DMIC sample rate */
+	if (pdata->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
+		switch (pdata->dmic_sample_rate) {
+		case WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+			break;
+		case WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
+			break;
+		case WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ:
+		case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s Invalid sample rate %d for mclk %d\n",
+				__func__, pdata->dmic_sample_rate,
+				pdata->mclk_rate);
+			rc = -EINVAL;
+			goto done;
+		}
+	} else if (pdata->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
+		switch (pdata->dmic_sample_rate) {
+		case WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+			break;
+		case WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
+			break;
+		case WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ:
+		case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s Invalid sample rate %d for mclk %d\n",
+				__func__, pdata->dmic_sample_rate,
+				pdata->mclk_rate);
+			rc = -EINVAL;
+			goto done;
+		}
+	} else {
+		dev_err(codec->dev, "%s MCLK is not set!\n", __func__);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	snd_soc_update_bits(codec, TAPAN_A_CDC_TX1_DMIC_CTL,
+		0x7, dmic_sample_rate_value);
+	snd_soc_update_bits(codec, TAPAN_A_CDC_TX2_DMIC_CTL,
+		0x7, dmic_sample_rate_value);
+	snd_soc_update_bits(codec, TAPAN_A_CDC_TX3_DMIC_CTL,
+		0x7, dmic_sample_rate_value);
+	snd_soc_update_bits(codec, TAPAN_A_CDC_TX4_DMIC_CTL,
+		0x7, dmic_sample_rate_value);
+	snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_DMIC_B1_CTL,
+		0xEE, dmic_b1_ctl_value);
+	snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B2_CTL,
+		0x1, anc_ctl_value);
+
 done:
 	return rc;
 }
@@ -4862,15 +4959,6 @@
 	{TAPAN_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
 	{TAPAN_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
 
-	/* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
-	{TAPAN_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
-	{TAPAN_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
-	{TAPAN_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
-	{TAPAN_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
-
-	/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
-	{TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
-
 	/* Compander zone selection */
 	{TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
 	{TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
@@ -4996,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)
@@ -5026,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;
@@ -5292,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,
@@ -5336,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;
@@ -5383,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);
@@ -5589,7 +5674,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 4ce9b4a..5656887 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -248,21 +248,6 @@
 
 #define TAIKO_I2S_MASTER_MODE_MASK 0x08
 
-#define TAIKO_DMIC_SAMPLE_RATE_DIV_2	0x0
-#define TAIKO_DMIC_SAMPLE_RATE_DIV_3	0x1
-#define TAIKO_DMIC_SAMPLE_RATE_DIV_4	0x2
-
-#define TAIKO_DMIC_B1_CTL_DIV_2 0x00
-#define TAIKO_DMIC_B1_CTL_DIV_3 0x22
-#define TAIKO_DMIC_B1_CTL_DIV_4 0x44
-
-#define TAIKO_DMIC_B2_CTL_DIV_2 0x00
-#define TAIKO_DMIC_B2_CTL_DIV_3 0x02
-#define TAIKO_DMIC_B2_CTL_DIV_4 0x04
-
-#define TAIKO_ANC_DMIC_X2_ON	0x1
-#define TAIKO_ANC_DMIC_X2_OFF	0x0
-
 #define TAIKO_SLIM_CLOSE_TIMEOUT 1000
 #define TAIKO_SLIM_IRQ_OVERFLOW (1 << 0)
 #define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
@@ -1142,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[] = {
 
@@ -1290,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,
@@ -2513,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,
@@ -5741,24 +5846,24 @@
 	/* Set the DMIC sample rate */
 	if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ) {
 		switch (pdata->dmic_sample_rate) {
-		case TAIKO_DMIC_SAMPLE_RATE_2P4MHZ:
-			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
-			dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_4;
-			dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_4;
-			anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+		case WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+			dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_4;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
 			break;
-		case TAIKO_DMIC_SAMPLE_RATE_4P8MHZ:
-			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_2;
-			dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_2;
-			dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_2;
-			anc_ctl_value = TAIKO_ANC_DMIC_X2_ON;
+		case WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+			dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_2;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
 			break;
-		case TAIKO_DMIC_SAMPLE_RATE_3P2MHZ:
-		case TAIKO_DMIC_SAMPLE_RATE_UNDEFINED:
-			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_3;
-			dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_3;
-			dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_3;
-			anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+		case WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ:
+		case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+			dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_3;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
 			break;
 		default:
 			pr_err("%s Invalid sample rate %d for mclk %d\n",
@@ -5769,24 +5874,24 @@
 		}
 	} else if (pdata->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ) {
 		switch (pdata->dmic_sample_rate) {
-		case TAIKO_DMIC_SAMPLE_RATE_3P072MHZ:
-			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
-			dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_4;
-			dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_4;
-			anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+		case WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+			dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_4;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
 			break;
-		case TAIKO_DMIC_SAMPLE_RATE_6P144MHZ:
-			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_2;
-			dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_2;
-			dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_2;
-			anc_ctl_value = TAIKO_ANC_DMIC_X2_ON;
+		case WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+			dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_2;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
 			break;
-		case TAIKO_DMIC_SAMPLE_RATE_4P096MHZ:
-		case TAIKO_DMIC_SAMPLE_RATE_UNDEFINED:
-			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_3;
-			dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_3;
-			dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_3;
-			anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+		case WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ:
+		case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+			dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+			dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+			dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_3;
+			anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
 			break;
 		default:
 			pr_err("%s Invalid sample rate %d for mclk %d\n",
@@ -6080,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)
@@ -6383,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;
@@ -6428,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
@@ -6617,7 +6738,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-common.h b/sound/soc/codecs/wcd9xxx-common.h
index e63d36a..0239c86 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -37,6 +37,21 @@
 #define	WCD9XXX_CLSH_STATE_LO (0x01 << 3)
 #define NUM_CLSH_STATES ((0x01 << 4) - 1)
 
+#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_2    0x0
+#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_3    0x1
+#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_4    0x2
+
+#define WCD9XXX_DMIC_B1_CTL_DIV_2 0x00
+#define WCD9XXX_DMIC_B1_CTL_DIV_3 0x22
+#define WCD9XXX_DMIC_B1_CTL_DIV_4 0x44
+
+#define WCD9XXX_DMIC_B2_CTL_DIV_2 0x00
+#define WCD9XXX_DMIC_B2_CTL_DIV_3 0x02
+#define WCD9XXX_DMIC_B2_CTL_DIV_4 0x04
+
+#define WCD9XXX_ANC_DMIC_X2_ON    0x1
+#define WCD9XXX_ANC_DMIC_X2_OFF   0x0
+
 /* Derived State: Bits 1 and 2 should be set for Headphone stereo */
 #define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
 						WCD9XXX_CLSH_STATE_HPHR)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a9e0c43..2ecebcd 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -118,13 +118,16 @@
 /* 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
 #define WCD9XXX_CS_MEAS_DELTA_MAX_MV 10
 
+static int impedance_detect_en;
+module_param(impedance_detect_en, int,
+			S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(impedance_detect_en, "enable/disable impedance detect");
+
 static bool detect_use_vddio_switch = true;
 
 struct wcd9xxx_mbhc_detect {
@@ -184,9 +187,11 @@
 	return mbhc->polling_active;
 }
 
-static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
 {
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+	struct snd_soc_codec *codec = mbhc->codec;
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			    0x04, on ? 0x04 : 0x00);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -296,7 +301,7 @@
 		override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
 			   0x04;
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, true);
+			wcd9xxx_turn_onoff_override(mbhc, true);
 		/* Adjust threshold if Mic Bias voltage changes */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
@@ -338,7 +343,7 @@
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    0x10, 0x00);
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		if (restartpolling)
 			wcd9xxx_start_hs_polling(mbhc);
 
@@ -563,7 +568,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;
@@ -574,13 +579,13 @@
 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,
@@ -861,7 +866,7 @@
 			mbhc->micbias_enable_cb(mbhc->codec, true);
 		}
 
-		if (mbhc->impedance_detect)
+		if (mbhc->impedance_detect && impedance_detect_en)
 			wcd9xxx_detect_impedance(mbhc, &mbhc->zl, &mbhc->zr);
 
 		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
@@ -965,7 +970,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);
 
@@ -1011,7 +1017,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;
 }
@@ -1049,6 +1056,27 @@
 					 mbhc->mbhc_data.micb_mv);
 }
 
+/* To enable/disable bandgap and RC oscillator */
+static void wcd9xxx_mbhc_ctrl_clk_bandgap(struct wcd9xxx_mbhc *mbhc,
+		bool enable)
+{
+	if (enable) {
+		WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
+		wcd9xxx_resmgr_get_bandgap(mbhc->resmgr,
+				WCD9XXX_BANDGAP_AUDIO_MODE);
+		wcd9xxx_resmgr_get_clk_block(mbhc->resmgr,
+				WCD9XXX_CLK_RCO);
+		WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+	} else {
+		WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
+		wcd9xxx_resmgr_put_clk_block(mbhc->resmgr,
+				WCD9XXX_CLK_RCO);
+		wcd9xxx_resmgr_put_bandgap(mbhc->resmgr,
+				WCD9XXX_BANDGAP_AUDIO_MODE);
+		WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+	}
+}
+
 /* called only from interrupt which is under codec_resource_lock acquisition */
 static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
 					   bool is_cs_enable)
@@ -1070,15 +1098,21 @@
 	}
 
 	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	/* Enable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
 
 	/*
-	 * Request BG and clock.
-	 * These will be released by wcd9xxx_cleanup_hs_polling
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
 	 */
-	WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-	wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
-	wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
-	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+	if (mbhc->mbhc_cfg->use_int_rbias) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+	else
+		pr_err("%s: internal bias is requested but codec did not provide callback\n",
+			 __func__);
+	}
 
 	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
 
@@ -1184,18 +1218,20 @@
 
 static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
+
+	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
 	wcd9xxx_shutdown_hs_removal_detect(mbhc);
 
-	/* Release clock and BG requested by wcd9xxx_mbhc_setup_hs_polling */
-	WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-	wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
-	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
-	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+
+	/* Disable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false);
 
 	mbhc->polling_active = false;
 	mbhc->mbhc_state = MBHC_STATE_NONE;
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -1209,6 +1245,12 @@
 static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
 {
 	pr_debug("%s: vddio %d\n", __func__, on);
+
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->pull_mb_to_vddio) {
+		mbhc->mbhc_cb->pull_mb_to_vddio(mbhc->codec, on);
+		goto exit;
+	}
+
 	if (on) {
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 1 << 7);
@@ -1220,6 +1262,12 @@
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 0);
 	}
+
+exit:
+	/*
+	 * Wait for the micbias to settle down to vddio
+	 * when the micbias to vddio switch is enabled.
+	 */
 	if (on)
 		usleep_range(10000, 10000);
 }
@@ -1382,7 +1430,7 @@
 		    (dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MAX_MV >
 		     maxv))
 			type = PLUG_TYPE_GND_MIC_SWAP;
-		else if (dgnd->_type != PLUG_TYPE_HEADSET) {
+		else if (dgnd->_type != PLUG_TYPE_HEADSET && !dmicbias) {
 			pr_debug("%s: Invalid, inconsistent types\n", __func__);
 			type = PLUG_TYPE_INVALID;
 		}
@@ -1650,6 +1698,7 @@
 
 	BUG_ON(NUM_DCE_PLUG_INS_DETECT < 4);
 
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
 	rt[0].swap_gnd = false;
 	rt[0].vddio = false;
 	rt[0].hwvalue = true;
@@ -1678,6 +1727,7 @@
 	type = wcd9xxx_cs_find_plug_type(mbhc, rt, ARRAY_SIZE(rt), highhph,
 					 mbhc->event_state);
 
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
 	pr_debug("%s: plug_type:%d\n", __func__, type);
 
 	return type;
@@ -1718,6 +1768,8 @@
 	 */
 	(void) wcd9xxx_pull_down_micbias(mbhc,
 					 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
+
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
 	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
 	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, false);
 	rt[0].swap_gnd = false;
@@ -1757,6 +1809,7 @@
 	type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt),
 				      mbhc->event_state);
 
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
 	pr_debug("%s: leave\n", __func__);
 	return type;
 }
@@ -1904,7 +1957,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__);
 
@@ -1945,6 +1998,8 @@
 		 * only report the mic line
 		 */
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
+		/* Button detection required RC oscillator */
+		wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
 		msleep(100);
 
 		/* if PA is already on, switch micbias source to VDDIO */
@@ -1988,7 +2043,6 @@
 static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
 {
 	enum wcd9xxx_mbhc_plug_type plug_type;
-	struct snd_soc_codec *codec = mbhc->codec;
 	bool current_source_enable;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2002,9 +2056,9 @@
 		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
 		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
 	} else {
-		wcd9xxx_turn_onoff_override(codec, true);
+		wcd9xxx_turn_onoff_override(mbhc, true);
 		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-		wcd9xxx_turn_onoff_override(codec, false);
+		wcd9xxx_turn_onoff_override(mbhc, false);
 	}
 
 	if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -2015,13 +2069,16 @@
 
 	if (plug_type == PLUG_TYPE_INVALID ||
 	    plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else {
@@ -2231,8 +2288,11 @@
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
 
-	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
-		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+	/* If micbias is enabled, don't enable current source */
+	cs_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0) &&
+		     (!(snd_soc_read(codec,
+				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 	if (cs_enable)
 		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
 
@@ -2274,6 +2334,9 @@
 				 * extension cable is still plugged in
 				 * report it as LINEOUT device
 				 */
+				if (mbhc->hph_status == SND_JACK_HEADSET)
+					wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc,
+							false);
 				wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
 				wcd9xxx_cleanup_hs_polling(mbhc);
 				wcd9xxx_enable_hs_detect(mbhc, 1,
@@ -2292,6 +2355,7 @@
 			wcd9xxx_switch_micbias(mbhc, 0);
 
 			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
+			wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
 			wcd9xxx_cleanup_hs_polling(mbhc);
 			wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
 							  MBHC_USE_HPHL_TRIGGER,
@@ -2368,7 +2432,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);
@@ -2435,7 +2499,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);
 }
@@ -2643,7 +2707,7 @@
 		wcd9xxx_turn_onoff_current_source(mbhc, true,
 						  false);
 	else
-		wcd9xxx_turn_onoff_override(codec, true);
+		wcd9xxx_turn_onoff_override(mbhc, true);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!time_after(jiffies, timeout)) {
@@ -2728,7 +2792,7 @@
 				wcd9xxx_turn_onoff_current_source(mbhc, false,
 								  false);
 			else
-				wcd9xxx_turn_onoff_override(codec, false);
+				wcd9xxx_turn_onoff_override(mbhc, false);
 			/*
 			 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
 			 */
@@ -2754,7 +2818,7 @@
 	if (!correction && current_source_enable)
 		wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
 	else if (!correction)
-		wcd9xxx_turn_onoff_override(codec, false);
+		wcd9xxx_turn_onoff_override(mbhc, false);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, false);
 
@@ -2804,6 +2868,10 @@
 		/* cancel detect plug */
 		wcd9xxx_cancel_hs_detect_plug(mbhc,
 					      &mbhc->correct_plug_swch);
+		if ((mbhc->current_plug != PLUG_TYPE_NONE) &&
+		    !(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DETECT) &
+				   (1 << 1)))
+			goto exit;
 
 		/* Disable Mic Bias pull down and HPH Switch to GND */
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01,
@@ -2826,6 +2894,7 @@
 			is_removed = true;
 		} else if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
 			wcd9xxx_pause_hs_polling(mbhc);
+			wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
 			wcd9xxx_cleanup_hs_polling(mbhc);
 			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
 			is_removed = true;
@@ -2853,10 +2922,10 @@
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
 					    0x08, 0x00);
 			/* Turn off override */
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		}
 	}
-
+exit:
 	mbhc->in_swch_irq_handler = false;
 	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 	pr_debug("%s: leave\n", __func__);
@@ -3004,13 +3073,14 @@
 	change = snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
 				     1 << 0);
 	usleep_range(1000, 1000 + 1000);
-	if (sta_z)
+	if (sta_z) {
 		*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
-	if (dce_z)
+		pr_debug("%s: sta_z 0x%x\n", __func__, *sta_z & 0xFFFF);
+	}
+	if (dce_z) {
 		*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
-
-	pr_debug("%s: sta_z 0x%x, dce_z 0x%x\n", __func__, *sta_z & 0xFFFF,
-		 *dce_z & 0xFFFF);
+		pr_debug("%s: dce_z 0x%x\n", __func__, *dce_z & 0xFFFF);
+	}
 
 	/* Connect override from micbias */
 	if (change)
@@ -3322,7 +3392,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,
@@ -3352,7 +3422,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);
@@ -3432,7 +3502,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() */
@@ -3443,7 +3514,13 @@
 	 * LDOH and CFILT are already configured during pdata handling.
 	 * Only need to make sure CFILT and bandgap are in Fast mode.
 	 * Need to restore defaults once calculation is done.
+	 *
+	 * In case when Micbias is powered by external source, request
+	 * turn on the external voltage source for Calibration.
 	 */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
+
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
 		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
@@ -3563,7 +3640,11 @@
 				    0x80, 0x80);
 	usleep_range(100, 100);
 
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	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,
+			   mbhc->intr_ids->dce_est_complete);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
 	pr_debug("%s: leave\n", __func__);
@@ -3629,14 +3710,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,
@@ -3659,13 +3733,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;
@@ -3695,9 +3770,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);
@@ -3923,6 +3998,18 @@
 		0x40, WCD9XXX_CFILT_FAST_MODE);
 
 	/*
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
+	 */
+	if (mbhc->mbhc_cfg->use_int_rbias) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+		else
+			pr_info("%s: internal bias is requested but codec did not provide callback\n",
+				__func__);
+	}
+
+	/*
 	 * If codec has specific clock gating for MBHC,
 	 * remove the clock gate
 	 */
@@ -4047,6 +4134,15 @@
 	return cfilt;
 }
 
+static void wcd9xxx_enable_mbhc_txfe(struct wcd9xxx_mbhc *mbhc, bool on)
+{
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mbhc_txfe)
+		mbhc->mbhc_cb->enable_mbhc_txfe(mbhc->codec, on);
+	else
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL,
+				    0x40, on ? 0x40 : 0x00);
+}
+
 static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
 				void *data)
 {
@@ -4064,14 +4160,22 @@
 	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias == wcd9xxx_event_to_micbias(event))
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
 			wcd9xxx_switch_micbias(mbhc, 0);
+			/*
+			 * Enable MBHC TxFE whenever  micbias is
+			 * turned ON and polling is active
+			 */
+			if (mbhc->polling_active)
+				wcd9xxx_enable_mbhc_txfe(mbhc, true);
+		}
 		break;
 	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias ==
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event) &&
 		    wcd9xxx_mbhc_polling(mbhc)) {
 			/* if polling is on, restart it */
@@ -4083,11 +4187,17 @@
 	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
-		if (mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event) &&
-		    (mbhc->event_state &
-		     (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
-			wcd9xxx_switch_micbias(mbhc, 1);
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
+			if (mbhc->event_state &
+			   (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.
+			 */
+			wcd9xxx_enable_mbhc_txfe(mbhc, false);
+		}
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
@@ -4253,18 +4363,15 @@
 	 */
 	mutex_lock(&codec->mutex);
 
-	WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
 	/*
 	 * 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_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
-	wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
-	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
 
-	wcd9xxx_turn_onoff_override(codec, true);
+	wcd9xxx_turn_onoff_override(mbhc, true);
 	pr_debug("%s: Setting impedance detection\n", __func__);
 
 	/* Codec specific setup for L0, R0, L1 and R1 measurements */
@@ -4310,12 +4417,9 @@
 
 	mutex_unlock(&codec->mutex);
 
-	WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
-	wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
-	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
 
-	wcd9xxx_turn_onoff_override(codec, false);
+	wcd9xxx_turn_onoff_override(mbhc, false);
 	mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
 
 	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
@@ -4352,7 +4456,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;
@@ -4379,7 +4485,14 @@
 	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,
@@ -4424,62 +4537,62 @@
 	wcd9xxx_init_debugfs(mbhc);
 
 	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);
@@ -4488,15 +4601,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);
 
@@ -4513,22 +4626,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 e5259c3..9d0afe9 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -227,6 +227,7 @@
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 	unsigned long cs_enable_flags;
+	bool use_int_rbias;
 };
 
 struct wcd9xxx_cfilt_mode {
@@ -235,21 +236,35 @@
 	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 *,
 			   enum mbhc_impedance_detect_stages stage);
 	void (*compute_impedance) (s16 *, s16 *, uint32_t *, uint32_t *);
+	void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
+	int (*enable_mb_source) (struct snd_soc_codec *, bool);
+	void (*setup_int_rbias) (struct snd_soc_codec *, bool);
+	void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
 };
 
 struct wcd9xxx_mbhc {
@@ -322,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;
@@ -390,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 95244c0..cb76342 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -199,12 +199,17 @@
 		usleep_range(50, 50);
 	}
 	/* Notify */
-	if (resmgr->clk_type == WCD9XXX_CLK_RCO)
+	if (resmgr->clk_type == WCD9XXX_CLK_RCO) {
 		wcd9xxx_resmgr_notifier_call(resmgr,
 					     WCD9XXX_EVENT_POST_RCO_OFF);
-	else
+	} else {
+		if (resmgr->codec_type == WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec,
+				MSM8X10_WCD_A_CDC_CLK_PDM_CTL, 0x03, 0x00);
+
 		wcd9xxx_resmgr_notifier_call(resmgr,
 					     WCD9XXX_EVENT_POST_MCLK_OFF);
+	}
 	pr_debug("%s: leave\n", __func__);
 }
 
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/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index 22bc9e1..470f44e 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -721,6 +721,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct voip_drv_info *prtd = runtime->private_data;
 	unsigned long dsp_flags;
+	int size;
 
 	count = frames_to_bytes(runtime, frames);
 
@@ -739,14 +740,19 @@
 					struct voip_buf_node, list);
 			list_del(&buf_node->list);
 			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
-			if (prtd->mode == MODE_PCM)
+			if (prtd->mode == MODE_PCM) {
 				ret = copy_to_user(buf,
 						   &buf_node->frame.voc_pkt,
-						   count);
-			else
+						   buf_node->frame.len);
+			} else {
+				size = sizeof(buf_node->frame.header) +
+				       sizeof(buf_node->frame.len) +
+				       buf_node->frame.len;
+
 				ret = copy_to_user(buf,
 						   &buf_node->frame,
-						   count);
+						   size;
+			}
 			if (ret) {
 				pr_err("%s: Copy to user retuned %d\n",
 					__func__, ret);
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 9460ec0..40de65b 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -939,21 +939,21 @@
 	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
 					       MBHC_BTN_DET_V_BTN_HIGH);
 	btn_low[0] = -50;
-	btn_high[0] = 10;
-	btn_low[1] = 11;
-	btn_high[1] = 52;
-	btn_low[2] = 53;
-	btn_high[2] = 94;
-	btn_low[3] = 95;
-	btn_high[3] = 133;
-	btn_low[4] = 134;
-	btn_high[4] = 171;
-	btn_low[5] = 172;
-	btn_high[5] = 208;
-	btn_low[6] = 209;
-	btn_high[6] = 244;
-	btn_low[7] = 245;
-	btn_high[7] = 330;
+	btn_high[0] = 20;
+	btn_low[1] = 21;
+	btn_high[1] = 61;
+	btn_low[2] = 62;
+	btn_high[2] = 104;
+	btn_low[3] = 105;
+	btn_high[3] = 148;
+	btn_low[4] = 149;
+	btn_high[4] = 189;
+	btn_low[5] = 190;
+	btn_high[5] = 228;
+	btn_low[6] = 229;
+	btn_high[6] = 269;
+	btn_low[7] = 270;
+	btn_high[7] = 500;
 	n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
 	n_ready[0] = 80;
 	n_ready[1] = 12;
@@ -2003,7 +2003,7 @@
 	mutex_init(&cdc_mclk_mutex);
 
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
-					"qcom,headset-jack-type-NO");
+					"qcom,headset-jack-type-NC");
 
 	ret = snd_soc_register_card(card);
 	if (ret == -EPROBE_DEFER)
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 23577ed..c318849 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -29,6 +29,7 @@
 #include <qdsp6v2/msm-pcm-routing-v2.h>
 #include <sound/q6afe-v2.h>
 #include <linux/module.h>
+#include <mach/gpiomux.h>
 #include "../codecs/msm8x10-wcd.h"
 #define DRV_NAME "msm8x10-asoc-wcd"
 #define BTSCO_RATE_8KHZ 8000
@@ -72,6 +73,7 @@
 	.detect_extn_cable = false,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.use_int_rbias = false,
 };
 
 /*
@@ -185,6 +187,10 @@
 
 static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
 {
+	/* set the drive strength on the clock */
+	msm_tlmm_misc_reg_write(TLMM_CDC_HDRV_CTL, 0x00);
+	msm_tlmm_misc_reg_write(TLMM_CDC_HDRV_PULL_CTL, 0x0006db6d);
+
 	iowrite32(0x1, pcbcr);
 	/* Set the update bit to make the settings go through */
 	iowrite32(0x1, prcgr);
@@ -1024,6 +1030,8 @@
 	atomic_set(&mclk_rsc_ref, 0);
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
 						"qcom,headset-jack-type-NC");
+	mbhc_cfg.use_int_rbias = of_property_read_bool(pdev->dev.of_node,
+						"qcom,mbhc-bias-internal");
 
 	spdev = pdev;
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index c9e38e0..93defcd 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -36,6 +36,7 @@
 #define NUM_VOCPROC_BLOCKS		(6 * MAX_NETWORKS)
 #define ACDB_TOTAL_VOICE_ALLOCATION	(ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS)
 
+#define MAX_HW_DELAY_ENTRIES	25
 
 struct sidetone_atomic_cal {
 	atomic_t	enable;
@@ -98,6 +99,10 @@
 
 	/* Speaker protection */
 	struct msm_spk_prot_cfg spk_prot_cfg;
+
+	/* Av sync delay info */
+	struct hw_delay hw_delay_rx;
+	struct hw_delay hw_delay_tx;
 };
 
 static struct acdb_data		acdb_data;
@@ -371,6 +376,122 @@
 	return result;
 }
 
+int get_hw_delay(int32_t path, struct hw_delay_entry *entry)
+{
+	int i, result = 0;
+	struct hw_delay *delay = NULL;
+	struct hw_delay_entry *info = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if (entry == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		result = -EINVAL;
+		goto ret;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		       __func__, path);
+		result = -EINVAL;
+		goto ret;
+	}
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay = &acdb_data.hw_delay_tx;
+
+	if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) {
+		pr_debug("ACDB=> %s Invalid delay/ delay entries\n", __func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	info = (struct hw_delay_entry *)(delay->delay_info);
+	if (info == NULL) {
+		pr_err("ACDB=> %s Delay entries info is NULL\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+	for (i = 0; i < delay->num_entries; i++) {
+		if (info[i].sample_rate == entry->sample_rate) {
+			entry->delay_usec = info[i].delay_usec;
+			break;
+		}
+	}
+	if (i == delay->num_entries) {
+		pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n",
+		       __func__, entry->sample_rate);
+		result = -EFAULT;
+	}
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+ret:
+	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
+		 __func__, path, entry->sample_rate, entry->delay_usec, result);
+	return result;
+}
+
+int store_hw_delay(int32_t path, void *arg)
+{
+	int result = 0;
+	struct hw_delay delay;
+	struct hw_delay *delay_dest = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) {
+		pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n",
+		      __func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+	result = copy_from_user((void *)&delay, (void *)arg,
+				sizeof(struct hw_delay));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n",
+		       __func__, result, path);
+		result = -EFAULT;
+		goto done;
+	}
+	if ((delay.num_entries <= 0) ||
+		(delay.num_entries > MAX_HW_DELAY_ENTRIES)) {
+		pr_debug("ACDB=> %s incorrect no of hw delay entries: %d\n",
+		       __func__, delay.num_entries);
+		result = -EINVAL;
+		goto done;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		__func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
+		 __func__, path, delay.num_entries);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay_dest = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay_dest = &acdb_data.hw_delay_tx;
+
+	delay_dest->num_entries = delay.num_entries;
+
+	result = copy_from_user(delay_dest->delay_info,
+				delay.delay_info,
+				(sizeof(struct hw_delay_entry)*
+				delay.num_entries));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d",
+		       __func__, result, path);
+		result = -EFAULT;
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return result;
+}
+
 int get_anc_cal(struct acdb_cal_block *cal_block)
 {
 	int result = 0;
@@ -998,9 +1119,33 @@
 	atomic_set(&acdb_data.valid_adm_custom_top, 1);
 	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 	atomic_inc(&usage_count);
+
 	return result;
 }
 
+static void allocate_hw_delay_entries(void)
+{
+	/* Allocate memory for hw delay entries */
+	acdb_data.hw_delay_rx.num_entries = 0;
+	acdb_data.hw_delay_tx.num_entries = 0;
+	acdb_data.hw_delay_rx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_rx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries rx\n",
+			__func__);
+	}
+	acdb_data.hw_delay_tx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_tx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries tx\n",
+			__func__);
+	}
+}
+
 static int unmap_cal_tables(void)
 {
 	int	result = 0;
@@ -1050,15 +1195,17 @@
 	int	i;
 	pr_debug("%s\n", __func__);
 
+	mutex_lock(&acdb_data.acdb_mutex);
+	kfree(acdb_data.hw_delay_tx.delay_info);
+	kfree(acdb_data.hw_delay_rx.delay_info);
+
 	if (atomic64_read(&acdb_data.mem_len)) {
-		mutex_lock(&acdb_data.acdb_mutex);
 		/* unmap all cal data */
 		result = unmap_cal_tables();
 		if (result < 0)
 			pr_err("%s: unmap_cal_tables failed, err = %d\n",
 				__func__, result);
 
-
 		atomic64_set(&acdb_data.mem_len, 0);
 
 		for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
@@ -1070,7 +1217,8 @@
 		acdb_data.ion_handle = NULL;
 		mutex_unlock(&acdb_data.acdb_mutex);
 	}
-	return result;
+	mutex_unlock(&acdb_data.acdb_mutex);
+	return 0;
 }
 
 static int register_memory(void)
@@ -1084,6 +1232,7 @@
 	pr_debug("%s\n", __func__);
 
 	mutex_lock(&acdb_data.acdb_mutex);
+	allocate_hw_delay_entries();
 	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
 		acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
 		atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
@@ -1238,6 +1387,12 @@
 	case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
 		result = deregister_vocvol_table();
 		goto done;
+	case AUDIO_SET_HW_DELAY_RX:
+		result = store_hw_delay(RX_CAL, (void *)arg);
+		goto done;
+	case AUDIO_SET_HW_DELAY_TX:
+		result = store_hw_delay(TX_CAL, (void *)arg);
+		goto done;
 	}
 
 	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index d9c1210..e2ca395 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -41,6 +41,11 @@
 	atomic_t		cal_paddr;
 };
 
+struct hw_delay_entry {
+	uint32_t sample_rate;
+	uint32_t delay_usec;
+};
+
 uint32_t get_voice_rx_topology(void);
 uint32_t get_voice_tx_topology(void);
 uint32_t get_adm_rx_topology(void);
@@ -65,5 +70,6 @@
 int get_sidetone_cal(struct sidetone_cal *cal_data);
 int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
 int get_aanc_cal(struct acdb_cal_block *cal_block);
+int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info);
 
 #endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index cd08b39..307d63e 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -43,75 +43,190 @@
 
 const struct dolby_dap_endp_params_s
 			dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
-	{EARPIECE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{SPEAKER,			2, DOLBY_ENDP_INT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADPHONE,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_HEADSET,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_CARKIT,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_HEADPHONES,	2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_SPEAKER,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{AUX_DIGITAL,			2, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			6, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			8, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{ANLG_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{DGTL_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_ACCESSORY,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_DEVICE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{REMOTE_SUBMIX,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADPHONE,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{PROXY,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM_TX,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
+	{EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADSET,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_HEADSET,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_ACCESSORY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{REMOTE_SUBMIX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADPHONE,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{PROXY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM_TX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
 };
 
 /* dolby param ids to/from dsp */
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 113d85f..4544fea 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -226,10 +226,17 @@
 #define DOLBY_PARAM_PAYLOAD_SIZE		3
 #define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM	329
 
-#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS		1
-#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET		0
-#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH		1
-#define DOLBY_ENDDEP_PARAM_LENGTH		DOLBY_ENDDEP_PARAM_DVLO_LENGTH
+#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS	  3
+#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET	  0
+#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH	  1
+#define DOLBY_ENDDEP_PARAM_DVLI_OFFSET    (DOLBY_ENDDEP_PARAM_DVLO_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLO_LENGTH)
+#define DOLBY_ENDDEP_PARAM_DVLI_LENGTH    1
+#define DOLBY_ENDDEP_PARAM_VMB_OFFSET     (DOLBY_ENDDEP_PARAM_DVLI_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLI_LENGTH)
+#define DOLBY_ENDDEP_PARAM_VMB_LENGTH     1
+#define DOLBY_ENDDEP_PARAM_LENGTH         (DOLBY_ENDDEP_PARAM_DVLO_LENGTH + \
+		DOLBY_ENDDEP_PARAM_DVLI_LENGTH + DOLBY_ENDDEP_PARAM_VMB_LENGTH)
 
 #define MAX_DOLBY_PARAMS			47
 #define MAX_DOLBY_CTRL_PARAMS			5
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index c4b44fe..d80ca19 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -35,8 +35,8 @@
 
 #define MIN_PLAYBACK_PERIOD_SIZE (128 * 2)
 #define MAX_PLAYBACK_PERIOD_SIZE (128 * 2 * 2 * 6)
-#define MIN_PLAYBACK_NUM_PERIODS (32)
-#define MAX_PLAYBACK_NUM_PERIODS (384)
+#define MIN_PLAYBACK_NUM_PERIODS (64)
+#define MAX_PLAYBACK_NUM_PERIODS (768)
 
 #define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
 #define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index caf77ee..c80d2a3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -290,6 +290,7 @@
 	struct output_meta_data_st output_meta_data;
 
 	pr_debug("%s: restart\n", __func__);
+	memset(&output_meta_data, 0x0, sizeof(struct output_meta_data_st));
 	if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
 		buf = prtd->audio_client->port[IN].buf;
 		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 62cc5db..1b4fae9 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -192,7 +192,7 @@
 		topology_id = get_adm_tx_topology();
 
 	if (topology_id  == 0)
-		topology_id = DEFAULT_COPP_TOPOLOGY;
+		topology_id = NULL_COPP_TOPOLOGY;
 
 	return topology_id;
 }
@@ -1344,7 +1344,7 @@
 		break;
 	case 1:
 		msm_route_ec_ref_rx = 1;
-		ec_ref_port_id = PRIMARY_I2S_RX;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 		break;
 	default:
 		msm_route_ec_ref_rx = 3; /* NONE */
@@ -1640,6 +1640,9 @@
 	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -1652,6 +1655,9 @@
 	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -1883,6 +1889,21 @@
 	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
@@ -3265,10 +3286,12 @@
 		/* incall */
 	{"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"Incall_Music Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"Incall_Music Audio Mixer", "MultiMedia9", "MM_DL9"},
 	{"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
 	{"Incall_Music_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"Incall_Music_2 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"Incall_Music_2 Audio Mixer", "MultiMedia5", "MM_DL5"},
 	{"Incall_Music_2 Audio Mixer", "MultiMedia9", "MM_DL9"},
 	{"VOICE2_PLAYBACK_TX", NULL, "Incall_Music_2 Audio Mixer"},
 	{"SLIMBUS_4_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3276,7 +3299,9 @@
 	{"SLIMBUS_4_RX", NULL, "SLIMBUS_4_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+	{"MultiMedia4 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+	{"MultiMedia4 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
 	{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -3371,11 +3396,14 @@
 	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+	{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MM_UL1", NULL, "MultiMedia1 Mixer"},
 	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 6cfc2ef..af25454 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -615,6 +615,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct voip_drv_info *prtd = runtime->private_data;
 	unsigned long dsp_flags;
+	int size;
 
 	count = frames_to_bytes(runtime, frames);
 
@@ -633,14 +634,19 @@
 					struct voip_buf_node, list);
 			list_del(&buf_node->list);
 			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
-			if (prtd->mode == MODE_PCM)
+			if (prtd->mode == MODE_PCM) {
 				ret = copy_to_user(buf,
 						   &buf_node->frame.voc_pkt,
-						   count);
-			else
+						   buf_node->frame.pktlen);
+			} else {
+				size = sizeof(buf_node->frame.frm_hdr) +
+				       sizeof(buf_node->frame.pktlen) +
+				       buf_node->frame.pktlen;
+
 				ret = copy_to_user(buf,
 						   &buf_node->frame,
-						   count);
+						   size);
+			}
 			if (ret) {
 				pr_err("%s: Copy to user retuned %d\n",
 					__func__, ret);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index bba4c14..27c74ce 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -36,7 +36,7 @@
 #define ADM_GET_PARAMETER_LENGTH  (4096 - APR_HDR_SIZE - 2 * sizeof(uint32_t))
 
 #define ULL_SUPPORTED_SAMPLE_RATE 48000
-
+#define ULL_MAX_SUPPORTED_CHANNEL 2
 enum {
 	ADM_RX_AUDPROC_CAL,
 	ADM_TX_AUDPROC_CAL,
@@ -1128,8 +1128,9 @@
 		if (perf_mode) {
 			open.topology_id = NULL_COPP_TOPOLOGY;
 			rate = ULL_SUPPORTED_SAMPLE_RATE;
+			if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
+				channel_mode = ULL_MAX_SUPPORTED_CHANNEL;
 		}
-
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
 		WARN_ON(perf_mode && (rate != 48000));
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index f7be34c..09ecd75 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -632,6 +632,71 @@
 	}
 }
 
+static int afe_send_hw_delay(u16 port_id, u32 rate)
+{
+	struct hw_delay_entry delay_entry;
+	struct afe_audioif_config_command config;
+	int index = 0;
+	int ret = -EINVAL;
+
+	pr_debug("%s\n", __func__);
+
+	delay_entry.sample_rate = rate;
+	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+		ret = get_hw_delay(TX_CAL, &delay_entry);
+	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+		ret = get_hw_delay(RX_CAL, &delay_entry);
+
+	if (ret != 0) {
+		pr_debug("%s: Failed to get hw delay info\n", __func__);
+		goto fail_cmd;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_debug("%s: AFE port index invalid!\n", __func__);
+		goto fail_cmd;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port_id);
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
+	config.pdata.param_size = sizeof(config.port);
+
+	config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
+	config.port.hw_delay.device_hw_delay_minor_version =
+				AFE_API_VERSION_DEVICE_HW_DELAY;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE hw delay for port %#x failed\n",
+		       __func__, port_id);
+		goto fail_cmd;
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	pr_debug("%s port_id %u rate %u delay_usec %d status %d\n",
+	__func__, port_id, rate, delay_entry.delay_usec, ret);
+	return ret;
+
+}
+
 void afe_send_cal(u16 port_id)
 {
 	pr_debug("%s\n", __func__);
@@ -1248,6 +1313,7 @@
 		return ret;
 
 	afe_send_cal(port_id);
+	afe_send_hw_delay(port_id, rate);
 
 	/* Start SW MAD module */
 	mad_type = afe_port_get_mad_type(port_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 76812f1..9c0c362 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1607,7 +1607,7 @@
 
 	open.preprocopo_id = get_asm_topology();
 	if (open.preprocopo_id == 0)
-		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
@@ -1706,7 +1706,7 @@
 
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (format) {
 	case FORMAT_LINEAR_PCM:
@@ -1790,7 +1790,7 @@
 	/* source endpoint : matrix */
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (wr_format) {
 	case FORMAT_LINEAR_PCM:
@@ -2237,7 +2237,6 @@
 			uint16_t sce_left, uint16_t sce_right)
 {
 	struct asm_aac_dual_mono_mapping_param dual_mono;
-	u32 frames_per_buf = 0;
 
 	int rc = 0;
 
@@ -2248,11 +2247,8 @@
 
 	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
-	dual_mono.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
-				sizeof(struct asm_stream_cmd_set_encdec_param);
-	dual_mono.encblk.frames_per_buf = frames_per_buf;
-	dual_mono.encblk.enc_cfg_blk_size  = dual_mono.encdec.param_size -
-				sizeof(struct asm_enc_cfg_blk_param_v2);
+	dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
+				sizeof(dual_mono.right_channel_sce);
 	dual_mono.left_channel_sce = sce_left;
 	dual_mono.right_channel_sce = sce_right;
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index de98feb..55f8dc8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3231,8 +3231,11 @@
 	mutex_init(&card->dapm_power_mutex);
 
 	ret = snd_soc_instantiate_card(card);
-	if (ret != 0)
+	if (ret != 0) {
 		soc_cleanup_card_debugfs(card);
+		if (card->rtd)
+			kfree(card->rtd);
+	}
 
 
 	return ret;