Merge "ASoC: msm: qdsp6v2: Use capital letter in VSID define"
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 2214f12..755d817 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -72,6 +72,8 @@
 	- misc. LCD driver documentation (cfag12864b, ks0108).
 basic_profiling.txt
 	- basic instructions for those who wants to profile Linux kernel.
+bif-framework.txt
+	- information about MIPI-BIF support in the Linux kernel.
 binfmt_misc.txt
 	- info on the kernel support for extra binary formats.
 blackfin/
diff --git a/Documentation/bif-framework.txt b/Documentation/bif-framework.txt
new file mode 100644
index 0000000..3ba500d
--- /dev/null
+++ b/Documentation/bif-framework.txt
@@ -0,0 +1,508 @@
+Introduction
+============
+
+BIF (Battery Interface) is a MIPI (Mobile Industry Processor Interface)
+Alliance specification for a serial interface between a host device and a
+battery pack.  It provides a means to handle smart battery packs which can
+communicate over BIF as well as low cost battery packs which provide no
+serial communication interface.
+
+The BIF bus supports 1 master and up to 256 slaves.  It supports data rates
+up to 250 kbps.  The master is in charge of initiating all bus
+communications.  Slaves may only respond asynchronously when they need to
+signal the master that they have an interrupt pending and when the bus is
+configured for interrupt mode.
+
+The BIF framework consists of a core into which BIF controller drivers
+register.  At runtime, consumers are notified of various events (e.g. battery
+insertion and battery removal) via a notifier.  Various framework functions are
+available for consumers to read and write slave registers as well as to send
+arbitrary BIF commands on the bus.
+
+Hardware description
+====================
+
+The BIF bus is a 1-wire wired-or interface.  The bus signal is referred to as
+the battery communication line (BCL).  The BCL is pulled high by a resistor on
+the host side and is driven low when the master or one of the slaves is
+communicating.  Additionally, there is a pull down resistor in the battery
+pack which is used to identify whether or not the battery pack has BIF slaves.
+Battery removal detection is achieved by comparing the analog voltage of the BCL
+when idle to the host side reference voltage.  If these voltages are within a
+certain threshold, then a battery pack is not present.
+
+Slaves are addressed on the BIF bus using an 8-bit device address (DEV_ADR).
+Notably, it is possible for no slaves to have defined DEV_ADR.  In this case,
+slave addressing is achieved via the always present unique ID (UID).  The UID
+of a slave is 80 bits long and guaranteed to be globally unique.  A UID search
+algorithm can be followed in order determine the UID of all slaves on the bus.
+
+BIF slaves come in two varieties: primary and secondary.  A single primary
+slave may be present on the battery pack and a single primary slave may be
+present on the host.  A battery pack primary slave has DEV_ADR=0x01.  The
+DEV_ADR of a host primary slave is set by the manufacturer.  A given primary
+slave contains a list of the UIDs of all secondary slaves in the same
+subsystem.  This provides a fast mechanism to determine the address of all
+slaves without having to resort to the lengthy UID search algorithm.
+
+Each slave has a 64 kB address space.  Part of this address space consists of
+generic DDB L1 and L2 data structures at known addresses.  This allows for
+runtime discovery of supported battery properties and functions of a given
+smart battery pack.
+
+System Diagram:
+ +-------------------------------+         +---------------------------------+
+ |           Host                |         |        Smart Battery Pack       |
+ |                               |         |                                 |
+ |                         Vbat-<+>-------<+>----------------------------+   |
+ |                               |         |                             |   |
+ |  +--------------+             |         |          +--------------+   |   |
+ |  | Master   BIF<+>-+---------<+>--BCL--<+>------+-<+>BIF Primary  |   |   |
+ |  |              |  |          |         |       |  |     Slave    |   |   |
+ |  +--------------+  |          |         |       |  +--------------+   |   |
+ |                    |          |         |       |                     |   |
+ |  + - - - - - - -+  |          |         |       |  + - - - - - - -+   |   |
+ |  | Primary  BIF<+>-+          |         |       +-<+>BIF Secondary|   |   |
+ |  | Slave        |  |          |         |       |  |     Slave    |   |   |
+ |  +- - - - - - - +  |          |         |       |  +-- - - - - - -+   |   |
+ |                    |          |         |       |                     |   |
+ |  + - - - - - - -+  |          |         |       |  + - - - - - - -+   |   |
+ |  |Secondary BIF<+>-+          |         |       +-<+>BIF Secondary|   |   |
+ |  |Slave         |  |          |         |       |  |     Slave    |   |   |
+ |  +- - - - - - - +  |          |         |       |  +-- - - - - - -+   |   |
+ |                    /          |         |       /                     |   |
+ |           Vref     \ Rpu      |         |   Rid \                   ----  |
+ |           ___      /          |         |       /           Battery  --   |
+ |            |       \          |         |       \            Cell   ----  |
+ |            +-------+          |         |       |                    --   |
+ |                               |         |       |                     |   |
+ |                          GND-<+>-------<+>------+---------------------+   |
+ |                               |         |                                 |
+ +-------------------------------+         +---------------------------------+
+
+An overview of BIF is available at:
+http://mipi.org/specifications/battery-interface
+
+Software description
+====================
+
+A given BIF hardware interface driver registers as a BIF controller in the
+BIF framework during its probe function.  The controller specifies a set of
+callback functions which are used by the BIF framework to initiate bus
+transactions (e.g. register read, register write, wait for slave interrupt)
+and to configure the bus.  The framework exposes a small API to controllers
+which is used to notify the framework about asynchronous events such as
+battery pack insertion/removal and slave interrupts.
+
+A given BIF consumer is linked to a BIF controller by specifying a property
+in the consumer's device tree node which takes as its value the phandle of
+the BIF controller's device tree node.
+
+A consumer driver calls a get function during its probe function with its
+device pointer in order to get a handle to the BIF controller if it has probed.
+If it hasn't, then ERR_PTR(-EPROBE_DEFER) is returned.  The controller handle
+can be used directly by the consumer to issue raw bus transactions if needed.
+The controller handle can then be used to query which slaves are currently
+present on the bus, if any.  Handles to these slaves may be used by a consumer
+driver in high level framework APIs such as register read and register write
+which are slave oriented.  All BIF framework API functions are synchronous,
+blocking, and can sleep.
+
+Consumer drivers may also register a notifier function which is called when
+certain bus activities occur such as battery pack insertion and removal.
+Additionally, consumer drivers may register a notifier function which is called
+when a specified slave interrupt fires.
+
+The framework maintains several linked-lists.  One list contains all controllers
+that have been registered.  A second list contains all slaves that have been
+seen since the system booted as well as a flag to indicate if they are currently
+present or not.  This scheme is used to avoid issues with slave handles existing
+after a slave is removed and also so that function and object values do not have
+to be searched when a slave is reinserted in the system since slaves are
+globally unique and these features are read-only.  Two further lists are
+maintained inside slave device structures which contain BIF functions and
+objects found in the slave.  API functions are provided so that consumers can
+find functions supported by slaves.
+
+Design
+======
+
+Design Goals:
+One major goal of the BIF framework is to provide a uniform API for BIF
+consumers to communicate with battery packs.  This ensures that consumers are
+unaffected by changes in the controller driver which actually interfaces with
+the BCL at a hardware level.
+
+Another goal of the framework is to ensure the BIF bus can be shared between
+multiple consumers in a simple and functionally correct way.  Locking is used
+inside of the framework to provide mutual exclusion on the bus.
+
+The framework also exposes features that almost all consumers will need, such
+as BIF slave identification and BIF function enumeration within a given slave.
+
+The framework allows consumers to issue very specific bus commands which may
+not be used within high level APIs.  This provides maximum flexibility so
+that consumers can make use of manufacturer defined bus commands which cannot be
+handled in a generic fashion.
+
+Design Trade-offs:
+The choice to not treat BIF like a traditional Linux bus was made because
+there is nothing within BIF that naturally maps to a device on the bus for a
+driver to manage.  Slave devices would be a good candidate except that
+consumers will not be managing slaves so much as functions exposed within
+slaves.  Bus matching could then instead be made at a BIF slave function
+level.  Unfortunately, the BIF specification allows for manufacturer specific
+features to reside at any non-defined addresses.  Additionally, consumers may
+wish only to read and make policy decisions based on BIF non-volatile memory
+(NVM) objects read out of memory.  Thus, there are use-cases that require
+consumers to utilize the bus without having a particular function to match to.
+
+Another trade-off was the choice to use custom interrupt handling functions
+instead of the Linux interrupt framework.  This choice was made because there is
+no obvious way to handle IRQ chip registration given the dynamic nature of BIF
+slaves (i.e. slaves may come and go at runtime if battery packs are swapped).
+
+Software layering:
+BIF controller drivers register a set of callback functions with the BIF
+framework which implement various BIF transaction primitives.  These
+callbacks ensure that tight timing constraints are met such as when receiving
+a bus query response immediately after issuing a command.  Such actions
+cannot be carried out at the framework level as timing requirements are on
+the order of 32 us when using the maximum data rate.
+
+The BIF framework provides easy access to standard BIF features such as
+slave, functions, and interrupts.  The framework also ensures mutual exclusion
+between different BIF consumers.
+
+BIF consumer drivers make use of the API exposed by the framework in order
+utilize functionality found on smart battery packs.  One example of a
+consumer driver is a temperature monitoring driver which reads the
+temperature reported by the BIF temperature function on a BIF slave and
+reports it to the Linux thermal framework.
+
+Power Management
+================
+
+The framework does not perform any special actions during system suspend and
+resume.  Controller drivers may choose to enter low power states during
+suspend if they wish as long as it does not affect the logical state of the
+bus.
+
+SMP/multi-core
+==============
+
+Various linked lists are maintained inside of the framework which are
+protected by mutexes.  Mutex locks are also used during transactions at a bus
+level in order to ensure mutual exclusion between consumers of the bus.
+
+Performance
+===========
+
+The BIF bus is inherently slow.  Consumers should expect transactions to take
+a long time to execute.  Consumers are responsible for blocking suspend if
+their transactions must be completed before the system enters suspend.
+
+Interface - BIF Consumer API
+============================
+
+BIF framework structs, enums, and functions used by BIF consumers are defined in
+include/linux/bif/consumer.h
+
+Detailed descriptions of the BIF framework functions can be found in:
+drivers/bif/bif-core.c
+
+Get/put handle for a BIF controller:
+------------------------------------
+
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev);
+
+void bif_ctrl_put(struct bif_ctrl *ctrl);
+
+int bif_ctrl_count(void);
+
+struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id);
+
+The function bif_ctrl_get() is intended to be the primary way to get a consumer
+BIF controller handle.  It relies upon the consumer device specifying a
+"qcom,bif-ctrl" property in its device tree node which points to the phandle of
+the BIF controller it wishes to use.
+
+A secondary mechanism is also provided for drivers without device tree support.
+bif_ctrl_count() returns the number of BIF controllers currently registered.
+bif_ctrl_get_by_id() returns a handle to the id'th controller enumerated in
+registration order.
+
+Get/put handle for a BIF slave:
+-------------------------------
+
+int bif_slave_match_count(const struct bif_ctrl *ctrl,
+			const struct bif_match_criteria *match_criteria);
+
+struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+	unsigned int id, const struct bif_match_criteria *match_criteria);
+
+void bif_slave_put(struct bif_slave *slave);
+
+A consumer finds a slave attached to a given BIF controller by specifying a set
+of matching criteria.  The criteria can include such quantities as manufacturer
+ID, product ID, function type or function version.  It is possible that multiple
+slaves will match the criteria.  bif_slave_match_count() returns how many slaves
+match the specified criteria.  bif_slave_match_get() returns the id'th slave
+which matches the criteria in an arbitrary, but fixed order (for a constant set
+of slaves).  Consumer drivers need to be able to handle the case of multiple
+slaves matching the criteria.
+
+Additionally, if a battery pack is inserted or removed, then the output of
+bif_slave_match_count() and bif_slave_match_get() could change.  A consumer
+driver can register to receive notification of battery pack insertion and
+removal using the bif_ctrl_notifier_register() function listed below.
+
+Check if slave handle is still meaningful:
+------------------------------------------
+
+int bif_slave_is_present(struct bif_slave *slave);
+
+If a battery pack is removed, then the handles for its slaves will no longer be
+meaningful.  All transactions using a handle for a slave that isn't present will
+fail.  The function bif_slave_is_present() allows a consumer to determine if
+a given slave is still physically present in the system.
+
+Get access to the controller handle present in a slave handle:
+--------------------------------------------------------------
+
+struct bif_ctrl *bif_get_ctrl_handle(struct bif_slave *slave);
+
+This function is useful if a consumer wishes to only store a slave handle but
+also has need to call bus oriented BIF framework functions.
+
+Get version and register offset of a BIF function if it is present in a slave:
+------------------------------------------------------------------------------
+
+int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
+				u16 *function_pointer);
+
+This function is used by consumers who wish to support given BIF functions
+(e.g. temperature measurement, authentication, etc.) found inside of slaves.
+
+Receive notification upon battery insertion and removal:
+--------------------------------------------------------
+
+int bif_ctrl_notifier_register(struct bif_ctrl *ctrl,
+				struct notifier_block *nb);
+
+int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+				struct notifier_block *nb);
+
+
+Read or write BIF slave registers:
+----------------------------------
+
+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);
+
+
+Get or set the BIF bus state or period:
+---------------------------------------
+
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl);
+
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state);
+
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl);
+
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns);
+
+Bus states include: active for communication, active waiting for interrupt,
+standby, and power down.  The MIPI-BIF specification defines the allowed range
+of bus periods as 2000 ns to 153000 ns.  Individual controllers may further
+restrict the range of allowed periods.  When bif_ctrl_set_bus_period() is called
+the first supported period that greater than or equal to the specified period
+will be set.
+
+Measure battery pack resistance:
+--------------------------------
+
+int bif_ctrl_measure_rid(struct bif_ctrl *ctrl);
+
+This function returns an estimate of the battery pack resistance in ohms.  If
+no battery pack is connected, then the output of this function is undefined.
+
+Utilize BIF slave tasks and interrupts:
+---------------------------------------
+
+int bif_request_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb);
+
+int bif_free_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb);
+
+int bif_trigger_task(struct bif_slave *slave, unsigned int task);
+
+int bif_task_is_busy(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.
+
+Raw BIF bus transactions:
+-------------------------
+
+void bif_ctrl_bus_lock(struct bif_ctrl *ctrl);
+
+void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl);
+
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data);
+
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+					u8 data, int *response);
+
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+		u8 data, bool *query_response);
+
+int bif_slave_is_selected(struct bif_slave *slave);
+
+int bif_slave_select(struct bif_slave *slave);
+
+The function bif_ctrl_bus_lock() locks the BIF bus for exclusive use by the
+consumer.  No other transactions will be allowed on the bus including those
+that would arise from battery insertion/removal or slave interrupt reception.
+This lock is primarily intended to be used along with the raw transaction
+functions.  These functions allow a consumer to issue any BIF transaction
+including manufacturer specific bus commands not handled by the BIF framework.
+
+While performing raw transactions, features normally performed transparently by
+the core, such as device selection, are not available.  The functions
+bif_slave_select() and bif_slave_is_selected() can be used to fill in this gap
+so that raw transactions are performed on the desired slave.
+
+Notify the BIF core that a battery has been inserted or removed:
+----------------------------------------------------------------
+
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl);
+
+This function should only be called on systems where the BIF controller driver
+is architecturally unable to detect battery insertion and removal on its own.
+
+Perform BIF object CRC using CRC-CCITT algorithm:
+-------------------------------------------------
+
+u16 bif_crc_ccitt(const u8 *buffer, int len);
+
+Interface - BIF Controller API
+==============================
+
+BIF framework structs and functions used by BIF controllers are defined in:
+include/linux/bif/driver.h
+
+Ops found in struct bif_ctrl_ops:
+---------------------------------
+
+int (*bus_transaction) (struct bif_ctrl_dev *bdev, int transaction, u8 data);
+
+int (*bus_transaction_query) (struct bif_ctrl_dev *bdev, int transaction,
+				u8 data, bool *query_response);
+
+int (*bus_transaction_read) (struct bif_ctrl_dev *bdev, int transaction,
+				u8 data, int *response);
+
+int (*read_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+				u8 *data, int len);
+
+int (*write_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+				const u8 *data, int len);
+
+int (*get_bus_period) (struct bif_ctrl_dev *bdev);
+
+int (*set_bus_period) (struct bif_ctrl_dev *bdev, int period_ns);
+
+int (*get_battery_presence) (struct bif_ctrl_dev *bdev);
+
+int (*get_battery_rid) (struct bif_ctrl_dev *bdev);
+
+int (*get_bus_state) (struct bif_ctrl_dev *bdev);
+
+int (*set_bus_state) (struct bif_ctrl_dev *bdev, int state);
+
+A BIF controller driver registers a set of call back functions which instantiate
+these ops.  The BIF framework then calls these functions based on internal and
+consumer needs.
+
+The ops bus_transaction(), bus_transaction_query(), and bus_transaction_read()
+carry out the controller hardware specific actions to perform BIF transactions
+on the BIF bus.  These transactions result in no slave response, a pulse in
+response, or a word in response respectively.  The ops read_slave_registers()
+and write_slave_registers() internally must perform all transactions necessary
+to read and write to BIF slave registers.  These ops exist so that burst reads
+and writes can take place since these activities have very tight timing
+constraints that the BIF core cannot handle.
+
+The ops get_bus_period() and set_bus_period() return the current bus clock base
+period in nanoseconds and change the period to a new value respectively.  The
+ops get_bus_state() and set_bus_state() allow for monitoring and controlling the
+bus state (i.e. active for communication, active waiting for interrupt, standby,
+or power down).  The op get_battery_presence() returns if any battery pack
+(smart or low cost) is currently connected to the BCL.  The op get_battery_rid()
+returns a best estimate of the Rid battery pack pull down ID resistance in ohms
+which can be used to determine if the battery pack is smart or low cost.
+
+Register/unregister a BIF controller:
+-------------------------------------
+
+struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
+	struct device *dev, void *driver_data, struct device_node *of_node);
+
+void bif_ctrl_unregister(struct bif_ctrl_dev *bdev);
+
+Notify the BIF framework that a battery has been inserted or removed:
+---------------------------------------------------------------------
+
+int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev);
+
+The BIF core will then call the get_battery_presence() op internally to
+determine if the event is an insertion or removal.
+
+Notify the BIF framework that a slave interrupt has been received:
+------------------------------------------------------------------
+
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev);
+
+Upon receiving this call, the BIF core interrogates each slave to determine
+which slaves have pending interrupts.  It then iterates through all interrupts
+on those slaves clearing all pending interrupts and notifying any consumers
+waiting for the interrupts.
+
+Get BIF controller private data:
+--------------------------------
+
+void *bdev_get_drvdata(struct bif_ctrl_dev *bdev);
+
+Config options
+==============
+
+CONFIG_BIF - Enables BIF framework support.
+
+User space utilities
+====================
+
+No user space interface is provided in the BIF framework.  Therefore, user
+space will not be able to directly use it.
+
+To do
+=====
+
+It is conceivable that the BIF framework should take some action during
+system suspend and resume.  However, it is not clear exactly what should be
+done given that the BCL would still need to be active in order to detect
+battery removal while suspended.
+
+sysfs nodes could be added which describe slaves as well as functions and
+objects within the slaves.  However these nodes would be read-only and would
+really only be useful for descriptive as opposed to control purposes.
+
+The exact time at which slave searching, function enumeration, and object
+loading takes place could be optimized in order to improve performance to
+some degree.  It could also be made configurable at a controller level if
+needed.
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
index 53a67a4..9616a94 100644
--- a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -7,6 +7,7 @@
 
 Optional properties:
 -qcom,satellite-mode: the hardware needs to be configured in satellite mode
+-qcom,rx-ring-size: the size of the receive ring buffer pool, default is 32
 
 Example:
 
@@ -15,4 +16,5 @@
 		reg = <0xfc834000 0x7000>;
 		interrupts = <0 29 1>;
 		qcom,satellite-mode;
+		qcom,rx-ring-size = <64>;
 	};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 0588c5e..b55bd53 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -55,6 +55,10 @@
 - label:		        	A string used as a descriptive name of the panel
 - qcom,enable-gpio:			Specifies the panel lcd/display enable gpio.
 - qcom,rst-gpio:			Specifies the panel reset gpio.
+- qcom,te-gpio:				Specifies the gpio used for TE.
+- qcom,dsi-lpg-channel :		LPG channel for backlight.
+- qcom,dsi-pwm-period :			PWM period in microseconds.
+- qcom,dsi-pwm-gpio :			PWM gpio.
 - qcom,mdss-pan-broadcast-mode:		Boolean used to enable broadcast mode.
 - qcom,cont-splash-enabled:		Boolean used to enable continuous splash mode.
 - qcom,mdss-pan-porch-values:		An array of size 6 that specifies the panel blanking values.
@@ -71,6 +75,15 @@
 - qcom,mdss-pan-dsi-mode:		Specifies the panel operating mode.
 					0 = enable video mode(default mode).
 					1 = enable command mode.
+- qcom,mdss-vsync-enable:		Specifies Tear Check configuration.
+					0 = TE disable.
+					1 = TE enable.
+- qcom,mdss-hw-vsync-mode:		Specifies TE type.
+					0 = software vsync.
+					1 = hardware vsync (TE gpio pin).
+- qcom,mdss-pan-te-sel:			Specifies TE operating mode.
+					0 = TE through embedded dcs command
+					1 = TE through TE gpio pin.
 - qcom,mdss-pan-dsi-h-pulse-mode:	Specifies the pulse mode option for the panel.
 					0 = Don't send hsa/he following vs/ve packet(default)
 					1 = Send hsa/he following vs/ve packet
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 497471a..0422b57 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -75,6 +75,12 @@
 				The number of dspp blocks should match the
 				number of mixers driving data to interface
 				defined in property: qcom,mdss-mixer-intf-off
+- qcom,mdss-pingpong-off:	Array of offset addresses for the available
+				pingpong blocks. These offsets are calculated
+				from regsiter "mdp_phys" defined in reg property.
+				The number of pingpong blocks should match the
+				number of mixers driving data to interface
+				defined in property: qcom,mdss-mixer-intf-off
 - qcom,mdss-mixer-wb-off: 	Array of offset addresses for the available
 				mixer blocks that can be drive data to writeback
 				block.  These offsets will be calculated from
@@ -142,6 +148,7 @@
 					    0x00003A00>;
 		qcom,mdss-mixer-wb-off = <0x00003E00 0x00004200>;
 		qcom,mdss-dspp-off = <0x00004600 0x00004A00 0x00004E00>;
+		qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
 		qcom,mdss-wb-off = <0x00011100 0x00013100 0x00015100
 				    0x00017100 0x00019100>;
 		qcom,mdss-intf-off = <0x00021100 0x00021300
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 812a895..4f31f07 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -30,7 +30,7 @@
 - qcom,ctrl-delay-us: delay in activation of led
 - qcom,dig-mod-gen-en: digital module generator
 - qcom,cs-out-en: current sink output enable
-- qcom,op-fdbck: selection of output as feedback for the boost
+- qcom,op-fdbck: selection of output as feedback for the boost, 00 = automatic selection, 01 = select LED1 output, 02 = select LED2 output, 03 = select LED3 output
 - qcom,cp-select: high pole capacitance
 - 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"
@@ -138,7 +138,7 @@
 				linux,default-trigger = "bkl-trigger"
 				label = "wled";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state "off";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index bebdb5a..2caa959 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -40,6 +40,8 @@
   (enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
   as "enum cp_mem_usage" in include/linux/msm_ion.h
 - qcom,has-ocmem: indicate the target has ocmem if this property exists
+- qcom,max-hw-load: The maximum load the hardware can support expressed in units
+  of macroblocks per second.
 
 Example:
 
@@ -73,4 +75,5 @@
 		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
 		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
 						<0x1fe 0x2>;
+		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
 	};
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index e3108ac..ad35985 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -13,6 +13,8 @@
 - interrupts: WCNSS to Apps watchdog bite interrupt
 - vdd_pronto_pll-supply: regulator to supply pronto pll.
 - qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
+- qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
 
 Example:
 	qcom,pronto@fb21b000 {
@@ -25,4 +27,10 @@
 		interrupts = <0 231 1>;
 
 		qcom,firmware-name = "wcnss";
+
+		/* GPIO input from wcnss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+
+		/* GPIO output to wcnss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
 	};
diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt
index 43033a8..ac82387 100644
--- a/Documentation/devicetree/bindings/qseecom/qseecom.txt
+++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt
@@ -3,6 +3,9 @@
 Required properties:
 - compatible : Should be "qcom,qseecom"
 - reg : should contain memory region address reserved for loading secure apps.
+- qcom,disk-encrypt-pipe-pair : indicates what CE HW pipe pair is used for disk encryption
+- qcom,hlos-ce-hw-instance : indicates what CE HW is used by HLOS crypto driver
+- qcom,qsee-ce-hw-instance : indicates what CE HW is used by secure domain (TZ) crypto driver
 - qcom, msm_bus,name: Should be "qseecom-noc"
 - qcom, msm_bus,num_cases: Depends on the use cases for bus scaling
 - qcom, msm_bus,num_paths: The paths for source and destination ports
@@ -13,6 +16,9 @@
 		compatible = "qcom,qseecom";
 		reg = <0x7f00000 0x500000>;
 		reg-names = "secapp-region";
+                qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,hlos-ce-hw-instance = <1>;
+		qcom,qsee-ce-hw-instance = <0>;
 		qcom,msm_bus,name = "qseecom-noc";
 		qcom,msm_bus,num_cases = <4>;
 		qcom,msm_bus,active_only = <0>;
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 989bea8..cbc77ad 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -2,21 +2,38 @@
 
 Required properties:
 
-  - compatible : "qcom,taiko-slim-pgd"
-  - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits)
+ - compatible : "qcom,taiko-slim-pgd"
+ - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits)
 
-  - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
+ - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
 
-  - <supply-name>-supply: phandle to the regulator device tree node
-  - qcom,<supply-name>-voltage - specifies voltage levels for supply.
-      Should be specified in pairs (min, max), units mV.
-  - qcom,<supply-name>-current - specifies max current in mA that can drawn
-      from the <supply-name>.
+ - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node.
+ - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buck-current: buck supply's max current in mA.
 
-    above three properties with "supply-name" set to "qcom,cdc-vdd-buck",
-        "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
-	"qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
-	should be present.
+ - cdc-vdd-tx-h-supply: phandle of tx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-tx-h-voltage: tx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-tx-h-current: tx-h supply's max current in mA.
+
+ - cdc-vdd-rx-h-supply: phandle of rx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-rx-h-voltage: rx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-rx-h-current: rx-h supply's max current in mA.
+
+ - cdc-vddpx-1-supply: phandle of px-1 supply's regulator device tree node.
+ - qcom,cdc-vddpx-1-voltage: px-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddpx-1-current: px-1 supply's max current in mA.
+
+ - cdc-vdd-a-1p2v-supply: phandle of 1.2v supply's regulator device tree node.
+ - qcom,cdc-vdd-a-1p2v-voltage: 1.2v supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-a-1p2v-current: 1.2v supply's max current in mA.
+
+ - cdc-vddcx-1-supply: phandle of cx-1 supply's regulator device tree node.
+ - qcom,cdc-vddcx-1-voltage: cx-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-1-current: cx-1 supply's max current in mA.
+
+ - cdc-vddcx-2-supply: phandle of cx-2 supply's regulator device tree node.
+ - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
 
  - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
 
@@ -99,19 +116,37 @@
 
 Wcd9xxx audio CODEC in I2C mode
 
-  - compatible = "qcom,wcd9xxx-i2c-device";
-  - reg: represents the slave address provided to the I2C driver.
-  - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
-  - <supply-name>-supply: phandle to the regulator device tree node.
-  - qcom,<supply-name>-voltage -  specifies voltage levels for supply.
-      Should be specified in pairs (min, max), units mV.
-  - qcom,<supply-name>-current - specifies max current in mA that can drawn
-      from the <supply-name>.
+ - compatible = "qcom,wcd9xxx-i2c-device";
+ - reg: represents the slave address provided to the I2C driver.
+ - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
 
-    above three properties with "supply-name" set to  "qcom,cdc-vdd-buck",
-    "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
-    "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
-    should be present.
+ - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node.
+ - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buck-current: buck supply's max current in mA.
+
+ - cdc-vdd-tx-h-supply: phandle of tx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-tx-h-voltage: tx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-tx-h-current: tx-h supply's max current in mA.
+
+ - cdc-vdd-rx-h-supply: phandle of rx-h supply's regulator device tree node.
+ - qcom,cdc-vdd-rx-h-voltage: rx-h supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-rx-h-current: rx-h supply's max current in mA.
+
+ - cdc-vddpx-1-supply: phandle of px-1 supply's regulator device tree node.
+ - qcom,cdc-vddpx-1-voltage: px-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddpx-1-current: px-1 supply's max current in mA.
+
+ - cdc-vdd-a-1p2v-supply: phandle of 1.2v supply's regulator device tree node.
+ - qcom,cdc-vdd-a-1p2v-voltage: 1.2v supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-a-1p2v-current: 1.2v supply's max current in mA.
+
+ - cdc-vddcx-1-supply: phandle of cx-1 supply's regulator device tree node.
+ - qcom,cdc-vddcx-1-voltage: cx-1 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-1-current: cx-1 supply's max current in mA.
+
+ - cdc-vddcx-2-supply: phandle of cx-2 supply's regulator device tree node.
+ - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
+ - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
 
  - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
 
@@ -121,13 +156,13 @@
    cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
 
  - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1
-     (should be from 1 to 3).
+				 (should be from 1 to 3).
  - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2
-     (should be from 1 to 3).
+				 (should be from 1 to 3).
  - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3
-     (should be from 1 to 3).
+				 (should be from 1 to 3).
  - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4
-     (should be from 1 to 3).
+				 (should be from 1 to 3).
    This value represents the connected CFLIT to MIC Bias.
 
  - qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 9761e01..2b1a352 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -724,7 +724,7 @@
 			};
 
 			chan@b5 {
-				label = "pa_therm1";
+				label = "pa_therm0";
 				reg = <0xb5>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
@@ -735,7 +735,7 @@
 			};
 
 			chan@b7 {
-				label = "pa_therm2";
+				label = "pa_therm1";
 				reg = <0xb7>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
@@ -814,7 +814,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x48>;
 			};
 
@@ -826,7 +826,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <1>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x68>;
 			};
 
@@ -838,7 +838,7 @@
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <1>;
 				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x88>;
 			};
 
@@ -850,32 +850,32 @@
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <3>;
 				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x90>;
 			};
 
 			chan@b5 {
-				label = "pa_therm1";
+				label = "pa_therm0";
 				reg = <0xb5>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x70>;
 				qcom,thermal-node;
 			};
 
 			chan@b7 {
-				label = "pa_therm2";
+				label = "pa_therm1";
 				reg = <0xb7>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x78>;
 				qcom,thermal-node;
 			};
@@ -888,7 +888,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x80>;
 				qcom,thermal-node;
 			};
@@ -901,7 +901,7 @@
 				qcom,calibration-type = "ratiometric";
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
+				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x98>;
 				qcom,thermal-node;
 			};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 8d8aa79..eab8b07 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -189,7 +189,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 35d329c..993b4e6 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -213,7 +213,7 @@
 		coresight-name = "coresight-csr";
 		coresight-nr-inports = <0>;
 
-		qcom,blk-size = <3>;
+		qcom,blk-size = <1>;
 	};
 
 	cti0: cti@fc308000 {
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 9c76512..7ab76f1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -32,6 +32,7 @@
 		qcom,mdss-mixer-intf-off = <0x00003200>;
 		qcom,mdss-mixer-wb-off = <0x00003E00>;
 		qcom,mdss-dspp-off = <0x00004600>;
+		qcom,mdss-pingpong-off = <0x00021B00>;
 		qcom,mdss-wb-off = <0x00011100 0x00013100>;
 		qcom,mdss-intf-off = <0x00000000 0x00021300>;
 		qcom,mdss-rot-block-size = <64>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 32d9a95..5c6fbd5 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -182,7 +182,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index ae97be9..df74bf9 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -185,7 +185,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 448a5be..9c21707 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -24,6 +24,29 @@
 	};
 };
 
+/* CPR controlled regulator */
+
+/ {
+	apc_vreg_corner: regulator@f9018000 {
+		status = "okay";
+		compatible = "qcom,cpr-regulator";
+		reg = <0xf9018000 0x1000>,
+			<0xfc4b80b0 8>;
+		reg-names = "rbcpr", "efuse_phys";
+		regulator-name = "apc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <4>;
+		qcom,num-efuse-bits = <5>;
+		qcom,efuse-bit-pos = <6 7 8 9 10>;
+		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		vdd-apc-supply = <&pm8226_s2>;
+	};
+};
+
 /* RPM controlled regulators: */
 
 &rpm_bus {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 25c534b..b34fa1f 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -96,6 +96,7 @@
 		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
 		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
 			<0x1fe 0x2>;
+		qcom,max-hw-load = <352800>; /* 720p @ 30 + 1080p @ 30 */
 	};
 
 	qcom,wfd {
@@ -574,7 +575,7 @@
 		compatible = "qcom,acpuclk-a7";
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
-		a7_cpu-supply = <&pm8226_s2>;
+		a7_cpu-supply = <&apc_vreg_corner>;
 		a7_mem-supply = <&pm8226_l3>;
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
new file mode 100644
index 0000000..f3a8259
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -0,0 +1,168 @@
+/* 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.
+ */
+/ {
+	msm_gpu: qcom,kgsl-3d0@fdc00000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		reg = <0xfdc00000 0x10000
+		       0xfdc10000 0x10000>;
+		reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_shader_memory";
+		interrupts = <0 33 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x03000520>;
+
+		qcom,initial-pwrlevel = <1>;
+
+		qcom,idle-timeout = <8>; /* <HZ/12> */
+		qcom,nap-allowed = <1>;
+		qcom,strtstp-sleepwake;
+		qcom,clk-map = <0x000001E>; /* KGSL_CLK_CORE |
+			KGSL_CLK_IFACE | KGSL_CLK_MEM | KGSL_CLK_MEM_IFACE */
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "grp3d";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<26 512 0 0>,
+			<26 512 0 800000>,
+			<26 512 0 1600000>,
+			<26 512 0 2128000>;
+
+		/* GDSC oxili regulators */
+		vdd-supply = <&gdsc_oxili_cx>;
+
+		/* IOMMU Data */
+		iommu = <&gfx_iommu>;
+
+		/* Power levels */
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <400000000>;
+				qcom,bus-freq = <3>;
+				qcom,io-fraction = <0>;
+			};
+
+			qcom,gpu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gpu-freq = <300000000>;
+				qcom,bus-freq = <2>;
+				qcom,io-fraction = <33>;
+			};
+
+			qcom,gpu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gpu-freq = <200000000>;
+				qcom,bus-freq = <2>;
+				qcom,io-fraction = <33>;
+			};
+
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <150000000>;
+				qcom,bus-freq = <1>;
+				qcom,io-fraction = <100>;
+			};
+
+			qcom,gpu-pwrlevel@4 {
+				reg = <4>;
+				qcom,gpu-freq = <27000000>;
+				qcom,bus-freq = <0>;
+				qcom,io-fraction = <0>;
+			};
+		};
+
+		/* DVCS Info */
+		qcom,dcvs-core-info {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,dcvs-core-info";
+
+			qcom,num-cores = <1>;
+			qcom,sensors = <0>;
+
+			qcom,core-core-type = <1>;
+
+			qcom,algo-disable-pc-threshold = <0>;
+			qcom,algo-em-win-size-min-us = <100000>;
+			qcom,algo-em-win-size-max-us = <300000>;
+			qcom,algo-em-max-util-pct = <97>;
+			qcom,algo-group-id = <95>;
+			qcom,algo-max-freq-chg-time-us = <100000>;
+			qcom,algo-slack-mode-dynamic = <100000>;
+			qcom,algo-slack-weight-thresh-pct = <0>;
+			qcom,algo-slack-time-min-us = <39000>;
+			qcom,algo-slack-time-max-us = <39000>;
+			qcom,algo-ss-win-size-min-us = <1000000>;
+			qcom,algo-ss-win-size-max-us = <1000000>;
+			qcom,algo-ss-util-pct = <95>;
+			qcom,algo-ss-no-corr-below-freq = <0>;
+
+			qcom,energy-active-coeff-a = <2492>;
+			qcom,energy-active-coeff-b = <0>;
+			qcom,energy-active-coeff-c = <0>;
+			qcom,energy-leakage-coeff-a = <11>;
+			qcom,energy-leakage-coeff-b = <157150>;
+			qcom,energy-leakage-coeff-c = <0>;
+			qcom,energy-leakage-coeff-d = <0>;
+
+			qcom,power-current-temp = <25>;
+			qcom,power-num-freq = <4>;
+
+			qcom,dcvs-freq@0 {
+				reg = <0>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@1 {
+				reg = <1>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@2 {
+				reg = <2>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <100>;
+				qcom,leakage-energy-offset = <0>;
+			};
+
+			qcom,dcvs-freq@3 {
+				reg = <3>;
+				qcom,freq = <0>;
+				qcom,voltage = <0>;
+				qcom,is_trans_level = <0>;
+				qcom,active-energy-offset = <844545>;
+				qcom,leakage-energy-offset = <0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f11f04b..5512ccd 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -23,6 +23,43 @@
 	};
 };
 
+/* SPM controlled regulators */
+
+&spmi_bus {
+	qcom,pm8110@1 {
+		pm8110_s2: spm-regulator@1700 {
+			compatible = "qcom,spm-regulator";
+			regulator-name = "8110_s2";
+			reg = <0x1700 0x100>;
+			regulator-min-microvolt = <900000>;
+			regulator-max-microvolt = <1350000>;
+		};
+	};
+};
+
+/* CPR controlled regulator */
+
+/ {
+	apc_vreg_corner: regulator@f9018000 {
+		status = "okay";
+		compatible = "qcom,cpr-regulator";
+		reg = <0xf9018000 0x1000>,
+			<0xfc4b80b0 8>;
+		reg-names = "rbcpr", "efuse_phys";
+		regulator-name = "apc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <4>;
+		qcom,num-efuse-bits = <5>;
+		qcom,efuse-bit-pos = <6 7 8 9 10>;
+		qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000 1200000>;
+		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000 1140000>;
+		vdd-apc-supply = <&pm8110_s2>;
+	};
+};
+
 /* QPNP controlled regulators: */
 
 &spmi_bus {
@@ -38,15 +75,6 @@
 			regulator-always-on;
 		};
 
-		pm8110_s2: regulator@1700 {
-			status = "okay";
-			regulator-min-microvolt = <1050000>;
-			regulator-max-microvolt = <1150000>;
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
-		};
-
 		pm8110_s3: regulator@1a00 {
 			status = "okay";
 			regulator-min-microvolt = <1350000>;
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
new file mode 100644
index 0000000..4a5273b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -0,0 +1,184 @@
+/* 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,smp2p-modem {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-adsp {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 158 1>;
+	};
+
+	qcom,smp2p-wcnss {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index d945619..124c318 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -13,9 +13,11 @@
 /include/ "skeleton.dtsi"
 /include/ "msm-iommu-v0.dtsi"
 /include/ "msm8610-ion.dtsi"
+/include/ "msm8610-gpu.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8610-coresight.dtsi"
 /include/ "msm8610-pm.dtsi"
+/include/ "msm8610-smp2p.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610";
@@ -77,6 +79,7 @@
 		qcom,buffer-type-tz-usage-map = <0x1 0x1>,
 						<0x1fe 0x2>;
 		qcom,hfi = "q6";
+		qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
 	};
 
 	usb@f9a55000 {
@@ -262,7 +265,7 @@
 		compatible = "qcom,acpuclk-a7";
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
-		a7_cpu-supply = <&pm8110_s2>;
+		a7_cpu-supply = <&apc_vreg_corner>;
 		a7_mem-supply = <&pm8110_l3>;
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index adab873..668b228 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -247,7 +247,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index e70d5d8..7c8b31c 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -224,7 +224,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index d61de02..02bc3ff 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -199,7 +199,7 @@
 				linux,name = "wled:backlight";
 				linux,default-trigger = "bkl-trigger";
 				qcom,cs-out-en;
-				qcom,op-fdbck;
+				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
 				qcom,max-current = <25>;
 				qcom,ctrl-delay-us = <0>;
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index bccf0fe..ae8cf83 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -56,6 +56,10 @@
 	qcom,write-64bit;
 };
 
+&mdss_mdp {
+	qcom,mdss-pingpong-off = <0x00021B00 0x00021C00 0x00021D00>;
+};
+
 &msm_vidc {
 	qcom,vidc-cp-map = <0x1000000 0x3f000000>;
 	qcom,vidc-ns-map = <0x40000000 0x40000000>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 16cdeb1..61f2c4f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -64,6 +64,7 @@
 			    0x00011900 0x00011D00 0x00012100>;
 	qcom,mdss-intf-off = <0x00012500 0x00012700
 			      0x00012900 0x00012b00>;
+	qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
 };
 
 &msm_vidc {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 7557657..52436b3 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -96,6 +96,7 @@
 		interrupts = <0 44 0>;
 		qcom,hfi = "venus";
 		qcom,has-ocmem;
+		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
 	};
 
 	qcom,vidc {
@@ -1097,6 +1098,9 @@
 		compatible = "qcom,qseecom";
 		reg = <0x7f00000 0x500000>;
 		reg-names = "secapp-region";
+		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,hlos-ce-hw-instance = <1>;
+		qcom,qsee-ce-hw-instance = <0>;
 		qcom,msm-bus,name = "qseecom-noc";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,active-only = <0>;
@@ -1266,6 +1270,7 @@
 		compatible = "qcom,bam_dmux";
 		reg = <0xfc834000 0x7000>;
 		interrupts = <0 29 1>;
+		qcom,rx-ring-size = <64>;
 	};
 
         qcom,msm-mem-hole {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index c0a945e..85738d0 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -57,6 +57,7 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ADSP_LOADER=m
 CONFIG_MSM_OCMEM=y
@@ -203,7 +204,6 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
-CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_WCNSS_CORE=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index ac51e25..db53ae5 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -428,6 +428,7 @@
 	select REGULATOR
 	select MSM_RPM_REGULATOR_SMD
 	select MSM_SPM_REGULATOR
+	select MSM_CPR_REGULATOR
 
 config ARCH_MSM8226
 	bool "MSM8226"
@@ -2642,8 +2643,6 @@
 
 config SENSORS_ADSP
 	bool "Enable Sensors Driver Support for ADSP"
-	depends on (ARCH_MSM8226 || ARCH_MSM8974)
-	default y
 	help
 	  Add support for sensors ADSP driver.
 	  This driver is used for exercising different sensors use cases,
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 73ea435..6e93c57 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/regulator/cpr-regulator.h>
 
 #include <mach/clk-provider.h>
 #include <mach/msm_bus.h>
@@ -53,13 +54,13 @@
  * 3) Depending on Frodo version, may need minimum of LVL_NOM
  */
 static struct clkctl_acpu_speed acpu_freq_tbl[] = {
-	{ 0,   19200, CXO,     0, 0,   1150000,   1150000, 0 },
-	{ 1,  300000, PLL0,    4, 2,   1150000,   1150000, 4 },
-	{ 1,  384000, ACPUPLL, 5, 0,   1150000,   1150000, 4 },
-	{ 1,  600000, PLL0,    4, 0,   1150000,   1150000, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
-	{ 0,  998400, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
+	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,   1150000, 0 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,   1150000, 4 },
+	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,   1150000, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL,   1150000, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL,   1150000, 7 },
+	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1150000, 7 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1150000, 7 },
 	{ 0 }
 };
 
@@ -67,8 +68,7 @@
 	.freq_tbl = acpu_freq_tbl,
 	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
-	/* FIXME regulator doesn't support corners yet */
-	.vdd_max_cpu = 1150000,
+	.vdd_max_cpu = CPR_CORNER_TURBO,
 	.vdd_max_mem = 1150000,
 	.src_clocks = {
 		[PLL0].name = "gpll0",
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 20c461d..cbb9e37 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -174,7 +174,7 @@
 #define A2_PHYS_BASE		0x124C2000
 #define A2_PHYS_SIZE		0x2000
 #define BUFFER_SIZE		2048
-#define NUM_BUFFERS		32
+#define DEFAULT_NUM_BUFFERS	32
 
 #ifndef A2_BAM_IRQ
 #define A2_BAM_IRQ -1
@@ -194,6 +194,7 @@
 static struct sps_register_event tx_register_event;
 static struct sps_register_event rx_register_event;
 static bool satellite_mode;
+static uint32_t num_buffers;
 
 static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
 static int bam_mux_initialized;
@@ -396,7 +397,7 @@
 	rx_len_cached = bam_rx_pool_len;
 	mutex_unlock(&bam_rx_pool_mutexlock);
 
-	while (bam_connection_is_active && rx_len_cached < NUM_BUFFERS) {
+	while (bam_connection_is_active && rx_len_cached < num_buffers) {
 		if (in_global_reset)
 			goto fail;
 
@@ -1182,14 +1183,14 @@
 				break;
 			}
 
-			buffs_used = NUM_BUFFERS - buffs_unused;
+			buffs_used = num_buffers - buffs_unused;
 
 			if (buffs_unused == 0) {
 				rx_timer_interval = MIN_POLLING_SLEEP;
 			} else {
 				if (buffs_used > 0) {
 					rx_timer_interval =
-						(2 * NUM_BUFFERS *
+						(2 * num_buffers *
 							rx_timer_interval)/
 						(3 * buffs_used);
 				} else {
@@ -2282,15 +2283,27 @@
 		satellite_mode = of_property_read_bool(pdev->dev.of_node,
 						"qcom,satellite-mode");
 
-		DBG("%s: base:%p size:%x irq:%d satellite:%d\n", __func__,
+		rc = of_property_read_u32(pdev->dev.of_node,
+						"qcom,rx-ring-size",
+						&num_buffers);
+		if (rc) {
+			DBG("%s: falling back to num_buffs default, rc:%d\n",
+							__func__, rc);
+			num_buffers = DEFAULT_NUM_BUFFERS;
+		}
+
+		DBG("%s: base:%p size:%x irq:%d satellite:%d num_buffs:%d\n",
+							__func__,
 							a2_phys_base,
 							a2_phys_size,
 							a2_bam_irq,
-							satellite_mode);
+							satellite_mode,
+							num_buffers);
 	} else { /* fallback to default init data */
 		a2_phys_base = (void *)(A2_PHYS_BASE);
 		a2_phys_size = A2_PHYS_SIZE;
 		a2_bam_irq = A2_BAM_IRQ;
+		num_buffers = DEFAULT_NUM_BUFFERS;
 	}
 
 	xo_clk = clk_get(&pdev->dev, "xo");
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index a1ed251..5ab4a53 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -475,6 +475,9 @@
 	.low_voltage_calc_ms		= 1000,
 	.alarm_low_mv			= 3400,
 	.alarm_high_mv			= 4000,
+	.high_ocv_correction_limit_uv	= 50,
+	.low_ocv_correction_limit_uv	= 100,
+	.hold_soc_est			= 3,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 4f398f4..ef65613 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -478,6 +478,9 @@
 	.low_voltage_calc_ms		= 1000,
 	.alarm_low_mv			= 3400,
 	.alarm_high_mv			= 4000,
+	.high_ocv_correction_limit_uv	= 50,
+	.low_ocv_correction_limit_uv	= 100,
+	.hold_soc_est			= 3,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 8c16984..c87d966 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -435,6 +435,9 @@
 	.low_voltage_calc_ms		= 1000,
 	.alarm_low_mv			= 3400,
 	.alarm_high_mv			= 4000,
+	.high_ocv_correction_limit_uv	= 50,
+	.low_ocv_correction_limit_uv	= 100,
+	.hold_soc_est			= 3,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index a645e9c..b7c46b4 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -345,9 +345,6 @@
 #define      gpll0_mm_source_val 5
 #define     gcc_xo_mm_source_val 0
 #define        mm_gnd_source_val 6
-#define     cxo_lpass_source_val 0
-#define lpapll0_lpass_source_val 1
-#define   gpll0_lpass_source_val 5
 #define     dsipll_mm_source_val 1
 
 #define F(f, s, div, m, n) \
@@ -404,17 +401,6 @@
 			| BVAL(10, 8, s##_mm_source_val), \
 	}
 
-#define F_LPASS(f, s, div, m, n) \
-	{ \
-		.freq_hz = (f), \
-		.src_clk = &s##_clk_src.c, \
-		.m_val = (m), \
-		.n_val = ~((n)-(m)) * !!(n), \
-		.d_val = ~(n),\
-		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
-			| BVAL(10, 8, s##_lpass_source_val), \
-	}
-
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
 	.vdd_class = &vdd_dig,			\
 	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
@@ -672,21 +658,6 @@
 	.base = &virt_bases[MMSS_BASE],
 };
 
-static struct pll_vote_clk lpapll0_clk_src = {
-	.en_reg = (void __iomem *)LPA_PLL_VOTE_APPS,
-	.en_mask = BIT(0),
-	.status_reg = (void __iomem *)LPAAUDIO_PLL_STATUS,
-	.status_mask = BIT(17),
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &gcc_xo_clk_src.c,
-		.rate = 491520000,
-		.dbg_name = "lpapll0_clk_src",
-		.ops = &clk_ops_pll_vote,
-		CLK_INIT(lpapll0_clk_src.c),
-	},
-};
-
 static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
 	F(  960000, gcc_xo, 10, 1, 2),
 	F( 4800000, gcc_xo,  4, 0, 0),
@@ -2227,197 +2198,6 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_audio_core_lpaif_clk[] = {
-	F_LPASS(  512000, lpapll0, 16, 1, 60),
-	F_LPASS(  768000, lpapll0, 16, 1, 40),
-	F_LPASS( 1024000, lpapll0, 16, 1, 30),
-	F_LPASS( 1536000, lpapll0, 16, 1, 20),
-	F_LPASS( 2048000, lpapll0, 16, 1, 15),
-	F_LPASS( 3072000, lpapll0, 16, 1, 10),
-	F_LPASS( 4096000, lpapll0, 15, 1,  8),
-	F_LPASS( 6144000, lpapll0, 10, 1,  8),
-	F_LPASS( 8192000, lpapll0, 15, 1,  4),
-	F_LPASS(12288000, lpapll0, 10, 1,  4),
-	F_END,
-};
-
-static struct rcg_clk lpaif_pri_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PRI_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pri_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_pri_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_quad_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_QUAD_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_quad_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_quad_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_sec_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_SEC_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_sec_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_sec_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_spkr_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_SPKR_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_spkr_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_spkr_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_ter_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_TER_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_ter_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
-		CLK_INIT(lpaif_ter_clk_src.c),
-	},
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_pcm0_1_clk[] = {
-	F_LPASS( 512000, lpapll0, 16, 1, 60),
-	F_LPASS( 768000, lpapll0, 16, 1, 40),
-	F_LPASS(1024000, lpapll0, 16, 1, 30),
-	F_LPASS(1536000, lpapll0, 16, 1, 20),
-	F_LPASS(2048000, lpapll0, 16, 1, 15),
-	F_LPASS(3072000, lpapll0, 16, 1, 10),
-	F_LPASS(4096000, lpapll0, 15, 1,  8),
-	F_LPASS(6144000, lpapll0, 10, 1,  8),
-	F_LPASS(8192000, lpapll0, 15, 1,  4),
-	F_END,
-};
-
-static struct rcg_clk lpaif_pcm0_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PCM0_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pcm0_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
-		CLK_INIT(lpaif_pcm0_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_pcm1_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PCM1_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pcm1_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
-		CLK_INIT(lpaif_pcm1_clk_src.c),
-	},
-};
-
-static struct rcg_clk lpaif_pcmoe_clk_src = {
-	.cmd_rcgr_reg =  LPAIF_PCMOE_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "lpaif_pcmoe_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 6140000, NOMINAL, 12290000),
-		CLK_INIT(lpaif_pcmoe_clk_src.c),
-	},
-};
-
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
-	F_LPASS(24576000, lpapll0, 4, 1, 5),
-	F_END
-};
-
-static struct rcg_clk audio_core_slimbus_core_clk_src = {
-	.cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_audio_core_slimbus_core_clock,
-	.current_freq = &rcg_dummy_freq,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_slimbus_core_clk_src",
-		.ops = &clk_ops_rcg_mnd,
-		VDD_DIG_FMAX_MAP2(LOW, 12935000, NOMINAL, 25869000),
-		CLK_INIT(audio_core_slimbus_core_clk_src.c),
-	},
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
-	.cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &audio_core_slimbus_core_clk_src.c,
-		.dbg_name = "audio_core_slimbus_core_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_slimbus_core_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_ixfabric_clk = {
-	.cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_ixfabric_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_ixfabric_clk.c),
-	},
-};
-
-static struct branch_clk audio_wrapper_br_clk = {
-	.cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_wrapper_br_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_wrapper_br_clk.c),
-	},
-};
-
 static struct branch_clk q6ss_ahb_lfabif_clk = {
 	.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
 	.has_sibling = 1,
@@ -2453,244 +2233,6 @@
 	},
 };
 
-static struct branch_clk audio_core_lpaif_pcm_data_oe_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pcmoe_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm_data_oe_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm_data_oe_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pri_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pri_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pri_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pri_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pcm0_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_quad_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_quad_clk_src.c,
-		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_quad_clk_src.c,
-		.dbg_name = "audio_core_lpaif_quad_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_sec_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_sec_clk_src.c,
-		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_sec_clk_src.c,
-		.dbg_name = "audio_core_lpaif_sec_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_pcm1_clk_src.c,
-		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
-	.has_sibling = 1,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_spkr_clk_src.c,
-		.dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_spkr_clk_src.c,
-		.dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.dbg_name = "audio_core_lpaif_ter_ebit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
-	.has_sibling = 0,
-	.max_div = 511,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_ter_clk_src.c,
-		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
-	},
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
-	.cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
-	.has_sibling = 0,
-	.base = &virt_bases[LPASS_BASE],
-	.c = {
-		.parent = &lpaif_ter_clk_src.c,
-		.dbg_name = "audio_core_lpaif_ter_osr_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
-	},
-};
-
 #ifdef CONFIG_DEBUG_FS
 
 struct measure_mux_entry {
@@ -2781,20 +2323,9 @@
 	{         &csi1pix_clk.c, MMSS_BASE, 0x0025},
 	{        &bimc_gfx_clk.c, MMSS_BASE, 0x0032},
 
-	{             &lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
-	{              &lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
-	{              &lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
-	{              &lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
-	{               &lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
-	{               &lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
-	{               &lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
-	{              &lpaif_spkr_clk_src.c, LPASS_BASE, 0x0018},
 	{                   &q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
 	{             &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
-	{            &audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
 	{                     &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
-	{&audio_core_lpaif_pcm_data_oe_clk.c, LPASS_BASE, 0x0030},
-	{         &audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
 
 	{&apc0_m_clk,                    APCS_BASE, 0x10},
 	{&apc1_m_clk,                    APCS_BASE, 0x11},
@@ -3232,40 +2763,6 @@
 							 "fd010000.qcom,iommu"),
 	CLK_LOOKUP("core_clk",         pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
 
-	CLK_LOOKUP("core_clk_src",                 lpaif_pri_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_quad_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                 lpaif_sec_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_spkr_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                 lpaif_ter_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_pcm0_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",                lpaif_pcm1_clk_src.c, ""),
-	CLK_LOOKUP("core_clk_src",               lpaif_pcmoe_clk_src.c, ""),
-	CLK_LOOKUP("core_clk",               audio_core_ixfabric_clk.c, ""),
-	CLK_LOOKUP("core_clk",                  audio_wrapper_br_clk.c, ""),
-	CLK_LOOKUP("core_clk",                   q6ss_ahb_lfabif_clk.c, ""),
-	CLK_LOOKUP("core_clk",                         q6ss_ahbm_clk.c, ""),
-	CLK_LOOKUP("core_clk",                           q6ss_xo_clk.c, ""),
-	CLK_LOOKUP("core_clk",      audio_core_lpaif_pcm_data_oe_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_pri_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_pri_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",          audio_core_lpaif_pri_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm0_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm0_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_quad_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_quad_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_quad_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_sec_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_sec_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",          audio_core_lpaif_sec_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm1_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm1_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",  audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",  audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",   audio_core_lpaif_codec_spkr_osr_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_ter_ebit_clk.c, ""),
-	CLK_LOOKUP("core_clk",         audio_core_lpaif_ter_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk",          audio_core_lpaif_ter_osr_clk.c, ""),
-
 	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
@@ -3316,32 +2813,6 @@
 	.size = ARRAY_SIZE(msm_clocks_8610_rumi),
 };
 
-static struct pll_config_regs gpll0_regs __initdata = {
-	.l_reg = (void __iomem *)GPLL0_L_VAL,
-	.m_reg = (void __iomem *)GPLL0_M_VAL,
-	.n_reg = (void __iomem *)GPLL0_N_VAL,
-	.config_reg = (void __iomem *)GPLL0_USER_CTL,
-	.mode_reg = (void __iomem *)GPLL0_MODE,
-	.base = &virt_bases[GCC_BASE],
-};
-
-/* GPLL0 at 600 MHz, main output enabled. */
-static struct pll_config gpll0_config __initdata = {
-	.l = 0x1f,
-	.m = 0x1,
-	.n = 0x4,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = 0x0,
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
 /* MMPLL0 at 800 MHz, main output enabled. */
 static struct pll_config mmpll0_config __initdata = {
 	.l = 0x29,
@@ -3376,32 +2847,6 @@
 	.main_output_mask = BIT(0),
 };
 
-static struct pll_config_regs lpapll0_regs __initdata = {
-	.l_reg = (void __iomem *)LPAAUDIO_PLL_L_VAL,
-	.m_reg = (void __iomem *)LPAAUDIO_PLL_M_VAL,
-	.n_reg = (void __iomem *)LPAAUDIO_PLL_N_VAL,
-	.config_reg = (void __iomem *)LPAAUDIO_PLL_USER_CTL,
-	.mode_reg = (void __iomem *)LPAAUDIO_PLL_MODE,
-	.base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
-	.l = 0x33,
-	.m = 0x1,
-	.n = 0x5,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = BVAL(14, 12, 0x1),
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
 #define PLL_AUX_OUTPUT_BIT 1
 #define PLL_AUX2_OUTPUT_BIT 2
 
@@ -3421,21 +2866,10 @@
 
 static void __init reg_init(void)
 {
-	u32 regval, status;
-	int ret;
-
-	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
-			& gpll0_clk_src.status_mask))
-		configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
+	u32 regval;
 
 	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
 	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
-	configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
-
-	/* Enable GPLL0's aux outputs. */
-	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
-	regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
-	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL));
 
 	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
 	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
@@ -3447,31 +2881,6 @@
 	 * register.
 	 */
 	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
-	/*
-	 * TODO: The following sequence enables the LPASS audio core GDSC.
-	 * Remove when this becomes unnecessary.
-	 */
-
-	/*
-	 * Disable HW trigger: collapse/restore occur based on registers writes.
-	 * Disable SW override: Use hardware state-machine for sequencing.
-	 */
-	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
-	/* Configure wait time between states. */
-	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
-	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
-	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
-	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-	regval &= ~BIT(0);
-	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
-	ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
-				status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
-	WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
 }
 
 static void __init msm8610_clock_post_init(void)
@@ -3489,8 +2898,6 @@
 	clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
 	clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
 	clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
-	clk_set_rate(&audio_core_slimbus_core_clk_src.c,
-			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
 }
 
 #define GCC_CC_PHYS		0xFC400000
@@ -3567,11 +2974,6 @@
 	/* TODO: Remove this once the bus driver is in place */
 	clk_set_rate(&axi_clk_src.c, 200000000);
 	clk_prepare_enable(&mmss_s0_axi_clk.c);
-
-	/* TODO: Temporarily enable a clock to allow access to LPASS core
-	 * registers.
-	 */
-	clk_prepare_enable(&audio_core_ixfabric_clk.c);
 }
 
 static int __init msm8610_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
index e7eca7b..f2c8d58 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ b/arch/arm/mach-msm/clock-mdss-8226.c
@@ -111,7 +111,7 @@
 static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
 {
 	if (pll_initialized) {
-		pll_pclk_rate = (rate * 3) / 2;
+		pll_pclk_rate = rate;
 		pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
 		return 0;
 	} else {
@@ -148,7 +148,7 @@
 	REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
 	REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
 
-	REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+	REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
 	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
 	REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
 	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 8e7f1fa..d866874 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -193,7 +193,7 @@
 static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
 {
 	if (pll_initialized) {
-		pll_pclk_rate = (rate * 3) / 2;
+		pll_pclk_rate = rate;
 		pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
 		return 0;
 	} else {
@@ -230,7 +230,7 @@
 	REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
 	REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
 	REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
-	REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+	REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
 
 	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
 	REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index d4c33e3..e70a0a8 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1093,6 +1093,7 @@
 	.num_iommu_table = 2,
 	.load_table = vidc_v4l2_load_table,
 	.num_load_table = 2,
+	.max_load = 800*480*30/256,
 };
 
 struct platform_device msm_device_vidc_v4l2 = {
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 3fa2d5e..35257b2 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -567,6 +567,8 @@
 	 */
 	int64_t **load_table;
 	int num_load_table;
+
+	uint32_t max_load;
 };
 
 struct vcap_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index cf59dd8..c20576a 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1261,7 +1261,7 @@
  *
  */
 int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
-		u32 tb_sel, u8 desc_sel);
+		u32 tb_sel, u32 desc_sel);
 
 #else
 static inline int sps_register_bam_device(const struct sps_bam_props
@@ -1421,7 +1421,7 @@
 }
 
 static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
-		u32 tb_sel, u8 pre_level)
+		u32 tb_sel, u32 desc_sel)
 {
 	return -EPERM;
 }
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 6bd087c..edaa60c 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -25,6 +25,7 @@
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
 #include <linux/wcnss_wlan.h>
+#include <linux/of_gpio.h>
 
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
@@ -82,6 +83,8 @@
 	bool crash;
 	struct delayed_work cancel_vote_work;
 	int irq;
+	unsigned int err_fatal_irq;
+	int force_stop_gpio;
 	struct ramdump_device *ramdump_dev;
 };
 
@@ -302,25 +305,22 @@
 	subsystem_restart_dev(drv->subsys);
 }
 
-static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
-					uint32_t new_state)
+static irqreturn_t wcnss_err_fatal_intr_handler(int irq, void *dev_id)
 {
-	struct pronto_data *drv = data;
+	struct pronto_data *drv = dev_id;
+
+	pr_err("Fatal error on the wcnss.\n");
 
 	drv->crash = true;
-
-	pr_err("wcnss smsm state changed\n");
-
-	if (!(new_state & SMSM_RESET))
-		return;
-
 	if (drv->restart_inprogress) {
-		pr_err("wcnss: Ignoring smsm reset req, restart in progress\n");
-		return;
+		pr_err("wcnss: Ignoring error fatal, restart in progress\n");
+		return IRQ_HANDLED;
 	}
 
 	drv->restart_inprogress = true;
 	restart_wcnss(drv);
+
+	return IRQ_HANDLED;
 }
 
 static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
@@ -389,7 +389,7 @@
 
 	pr_err("wcnss crash shutdown %d\n", drv->crash);
 	if (!drv->crash)
-		smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+		gpio_set_value(drv->force_stop_gpio, 1);
 }
 
 static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
@@ -407,7 +407,7 @@
 	struct pronto_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
-	int ret;
+	int ret, err_fatal_gpio, irq;
 	uint32_t regval;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -440,6 +440,23 @@
 	if (ret)
 		return ret;
 
+	err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-err-fatal", 0);
+	if (err_fatal_gpio < 0)
+		return err_fatal_gpio;
+
+	irq = gpio_to_irq(err_fatal_gpio);
+	if (irq < 0)
+		return irq;
+
+	drv->err_fatal_irq = irq;
+
+	drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
+			"qcom,gpio-force-stop", 0);
+	if (drv->force_stop_gpio < 0)
+		return drv->force_stop_gpio;
+
+
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = 10000;
@@ -478,11 +495,6 @@
 	if (ret)
 		return ret;
 
-	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
-					smsm_state_cb_hdlr, drv);
-	if (ret < 0)
-		goto err_smsm;
-
 	drv->subsys_desc.name = desc->name;
 	drv->subsys_desc.dev = &pdev->dev;
 	drv->subsys_desc.owner = THIS_MODULE;
@@ -506,6 +518,14 @@
 	if (ret < 0)
 		goto err_irq;
 
+	ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
+			wcnss_err_fatal_intr_handler,
+			IRQF_TRIGGER_RISING, "pil-pronto", drv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
+		goto err_irq;
+	}
+
 	drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
@@ -520,12 +540,10 @@
 	writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
 
 	return 0;
+
 err_irq:
 	subsys_unregister(drv->subsys);
 err_subsys:
-	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
-					smsm_state_cb_hdlr, drv);
-err_smsm:
 	pil_desc_release(desc);
 	return ret;
 }
@@ -534,8 +552,6 @@
 {
 	struct pronto_data *drv = platform_get_drvdata(pdev);
 	subsys_unregister(drv->subsys);
-	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
-					smsm_state_cb_hdlr, drv);
 	pil_desc_release(&drv->desc);
 	destroy_ramdump_device(drv->ramdump_dev);
 	return 0;
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 5969a3c..8a2c23f 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -32,22 +32,36 @@
 #include <mach/msm_smd.h>
 #include <mach/subsystem_restart.h>
 #include <mach/socinfo.h>
+#include <mach/msm_ipc_logging.h>
 
 #include "smd_private.h"
 
 #define MAX_SMD_TTYS 37
 #define MAX_TTY_BUF_SIZE 2048
 #define MAX_RA_WAKE_LOCK_NAME_LEN 32
+#define SMD_TTY_LOG_PAGES 2
 
+#define SMD_TTY_INFO(buf...) \
+do { \
+	if (smd_tty_log_ctx) { \
+		ipc_log_string(smd_tty_log_ctx, buf); \
+	} \
+} while (0)
+
+#define SMD_TTY_ERR(buf...) \
+do { \
+	if (smd_tty_log_ctx) \
+		ipc_log_string(smd_tty_log_ctx, buf); \
+	pr_err(buf); \
+} while (0)
+
+static void *smd_tty_log_ctx;
 static DEFINE_MUTEX(smd_tty_lock);
 
-static uint smd_tty_modem_wait;
-module_param_named(modem_wait, smd_tty_modem_wait,
-			uint, S_IRUGO | S_IWUSR | S_IWGRP);
-
 struct smd_tty_info {
 	smd_channel_t *ch;
 	struct tty_port port;
+	struct device *device_ptr;
 	struct wake_lock wake_lock;
 	int open_count;
 	struct tasklet_struct tty_tsklt;
@@ -58,6 +72,7 @@
 	int in_reset;
 	int in_reset_updated;
 	int is_open;
+	unsigned int open_wait;
 	wait_queue_head_t ch_opened_wait_queue;
 	spinlock_t reset_lock;
 	spinlock_t ra_lock;		/* Read Available Lock*/
@@ -120,6 +135,57 @@
 	spin_unlock_irqrestore(&info->reset_lock, flags);
 }
 
+static ssize_t open_timeout_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t n)
+{
+	unsigned int num_dev;
+	unsigned long wait;
+	if (dev == NULL) {
+		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+		return -EINVAL;
+	}
+	for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+		if (dev == smd_tty[num_dev].device_ptr)
+			break;
+	}
+	if (num_dev >= MAX_SMD_TTYS) {
+		SMD_TTY_ERR("[%s]: Device Not found", __func__);
+		return -EINVAL;
+	}
+	if (!kstrtoul(buf, 10, &wait)) {
+		smd_tty[num_dev].open_wait = wait;
+		return n;
+	} else {
+		SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
+			__func__, buf);
+		return -EINVAL;
+	}
+}
+
+static ssize_t open_timeout_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned int num_dev;
+
+	if (dev == NULL) {
+		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+		return -EINVAL;
+	}
+	for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+		if (dev == smd_tty[num_dev].device_ptr)
+			break;
+	}
+	if (num_dev >= MAX_SMD_TTYS)
+		SMD_TTY_ERR("[%s]: Device Not Found", __func__);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			smd_tty[num_dev].open_wait);
+}
+
+static DEVICE_ATTR
+	(open_timeout, 0664, open_timeout_show, open_timeout_store);
+
 static void smd_tty_read(unsigned long param)
 {
 	unsigned char *ptr;
@@ -165,7 +231,9 @@
 			** context here and nobody else could 'steal' our
 			** characters.
 			*/
-			printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
+			SMD_TTY_ERR(
+				"%s - Possible smd_tty_buffer mismatch for %s",
+				__func__, info->ch->name);
 		}
 
 		wake_lock_timeout(&info->wake_lock, HZ / 2);
@@ -270,6 +338,16 @@
 		if (peripheral) {
 			info->pil = subsystem_get(peripheral);
 			if (IS_ERR(info->pil)) {
+				SMD_TTY_INFO(
+					"%s failed on smd_tty device :%s subsystem_get failed for %s",
+					__func__, smd_tty[n].smd->port_name,
+					peripheral);
+				/*
+				 * Sleep, inorder to reduce the frequency of
+				 * retry by user-space modules and to avoid
+				 * possible watchdog bite.
+				 */
+				msleep((smd_tty[n].open_wait * 1000));
 				res = PTR_ERR(info->pil);
 				goto out;
 			}
@@ -292,21 +370,22 @@
 			 * Wait for a channel to be allocated so we know
 			 * the modem is ready enough.
 			 */
-			if (smd_tty_modem_wait) {
+			if (smd_tty[n].open_wait) {
 				res = wait_for_completion_interruptible_timeout(
 					&info->ch_allocated,
-					msecs_to_jiffies(smd_tty_modem_wait *
+					msecs_to_jiffies(smd_tty[n].open_wait *
 									1000));
 
 				if (res == 0) {
-					pr_err("Timed out waiting for SMD"
-								" channel\n");
+					SMD_TTY_INFO(
+						"Timed out waiting for SMD channel %s",
+						smd_tty[n].smd->port_name);
 					res = -ETIMEDOUT;
 					goto release_pil;
 				} else if (res < 0) {
-					pr_err("Error waiting for SMD channel:"
-									" %d\n",
-						res);
+					SMD_TTY_INFO(
+						"Error waiting for SMD channel %s : %d\n",
+						smd_tty[n].smd->port_name, res);
 					goto release_pil;
 				}
 
@@ -329,8 +408,10 @@
 							&info->ch, info,
 							smd_tty_notify);
 			if (res < 0) {
-				pr_err("%s: %s open failed %d\n", __func__,
-					smd_tty[n].smd->port_name, res);
+				SMD_TTY_INFO(
+					"%s: %s open failed %d\n",
+					__func__, smd_tty[n].smd->port_name,
+					res);
 				goto release_pil;
 			}
 
@@ -340,12 +421,16 @@
 			if (res == 0)
 				res = -ETIMEDOUT;
 			if (res < 0) {
-				pr_err("%s: wait for %s smd_open failed %d\n",
+				SMD_TTY_INFO(
+					"%s: wait for %s smd_open failed %d\n",
 					__func__, smd_tty[n].smd->port_name,
 					res);
 				goto release_pil;
 			}
 			res = 0;
+			SMD_TTY_INFO("%s with PID %u opened port %s",
+				current->comm, current->pid,
+				smd_tty[n].smd->port_name);
 		}
 	}
 
@@ -382,6 +467,9 @@
 			wake_lock_destroy(&info->wake_lock);
 			wake_lock_destroy(&info->ra_wake_lock);
 		}
+		SMD_TTY_INFO("%s with PID %u closed port %s",
+				current->comm, current->pid,
+				info->smd->port_name);
 		tty->driver_data = 0;
 		del_timer(&info->buf_req_timer);
 		if (info->ch) {
@@ -430,6 +518,8 @@
 	}
 	if (len > avail)
 		len = avail;
+	SMD_TTY_INFO("[WRITE]: PID %u -> port %s %x bytes",
+			current->pid, info->smd->port_name, len);
 
 	return smd_write(info->ch, buf, len);
 }
@@ -480,6 +570,8 @@
 		tiocm |= TIOCM_OUT2;
 		info->in_reset_updated = 0;
 	}
+	SMD_TTY_INFO("PID %u --> %s TIOCM is %x ",
+			current->pid, __func__, tiocm);
 	spin_unlock_irqrestore(&info->reset_lock, flags);
 
 	return tiocm;
@@ -493,6 +585,8 @@
 	if (info->in_reset)
 		return -ENETRESET;
 
+	SMD_TTY_INFO("PID %u --> %s Set: %x Clear: %x",
+			current->pid, __func__, set, clear);
 	return smd_tiocmset(info->ch, set, clear);
 }
 
@@ -540,11 +634,25 @@
 			return 0;
 		}
 	}
-	pr_err("%s: unknown device '%s'\n", __func__, pdev->name);
+	SMD_TTY_ERR("[ERR]%s: unknown device '%s'\n", __func__, pdev->name);
 
 	return -ENODEV;
 }
 
+/**
+ * smd_tty_log_init()- Init function for IPC logging
+ *
+ * Initialize the buffer that is used to provide the log information
+ * pertaining to the smd_tty module.
+ */
+static void smd_tty_log_init(void)
+{
+	smd_tty_log_ctx = ipc_log_context_create(SMD_TTY_LOG_PAGES,
+						"smd_tty");
+	if (!smd_tty_log_ctx)
+		pr_err("%s: Unable to create IPC log", __func__);
+}
+
 static struct tty_driver *smd_tty_driver;
 
 static int __init smd_tty_init(void)
@@ -554,9 +662,12 @@
 	int idx;
 	struct tty_port *port;
 
+	smd_tty_log_init();
 	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
-	if (smd_tty_driver == 0)
+	if (smd_tty_driver == 0) {
+		SMD_TTY_ERR("%s - Driver allocation failed", __func__);
 		return -ENOMEM;
+	}
 
 	smd_tty_driver->owner = THIS_MODULE;
 	smd_tty_driver->driver_name = "smd_tty_driver";
@@ -577,7 +688,7 @@
 	ret = tty_register_driver(smd_tty_driver);
 	if (ret) {
 		put_tty_driver(smd_tty_driver);
-		pr_err("%s: driver registration failed %d\n", __func__, ret);
+		SMD_TTY_ERR("%s: driver registration failed %d", __func__, ret);
 		return ret;
 	}
 
@@ -612,7 +723,14 @@
 		tty_port_init(port);
 		port->ops = &smd_tty_port_ops;
 		/* TODO: For kernel >= 3.7 use tty_port_register_device */
-		tty_register_device(smd_tty_driver, idx, 0);
+		smd_tty[idx].device_ptr =
+			tty_register_device(smd_tty_driver, idx, 0);
+		if (device_create_file(smd_tty[idx].device_ptr,
+					&dev_attr_open_timeout))
+			SMD_TTY_ERR(
+				"%s: Unable to create device attributes for %s",
+				__func__, smd_configs[n].port_name);
+
 		init_completion(&smd_tty[idx].ch_allocated);
 
 		/* register platform device */
@@ -628,7 +746,8 @@
 		ret = platform_driver_register(&smd_tty[idx].driver);
 
 		if (ret) {
-			pr_err("%s: init failed %d (%d)\n", __func__, idx, ret);
+			SMD_TTY_ERR(
+				"%s: init failed %d (%d)", __func__, idx, ret);
 			smd_tty[idx].driver.probe = NULL;
 			goto out;
 		}
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 45c9023..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -227,7 +227,7 @@
 
 	pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
 		(unsigned long)base, (unsigned long)size / SZ_1M);
-	dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+	dma_contiguous_reserve_area(size, &base, 0, name);
 
 	return 0;
 }
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 555ffa0..6f37608 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -270,6 +270,7 @@
 	unsigned char *hdlc_buf;
 	unsigned hdlc_count;
 	unsigned hdlc_escape;
+	int in_busy_pktdata;
 #ifdef CONFIG_DIAG_OVER_USB
 	int usb_connected;
 	struct usb_diag_ch *legacy_ch;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index fb8efe4..a0c32f5 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1310,6 +1310,7 @@
 		COPY_USER_SPACE_OR_EXIT(buf+4, *(driver->pkt_buf),
 							 driver->pkt_length);
 		driver->data_ready[index] ^= PKT_TYPE;
+		driver->in_busy_pktdata = 0;
 		goto exit;
 	}
 
@@ -1397,6 +1398,117 @@
 							payload_size);
 		return err;
 	}
+	if (pkt_type == CALLBACK_DATA_TYPE) {
+		err = copy_from_user(driver->user_space_data, buf + 4,
+							 payload_size);
+		 if (err) {
+			pr_err("diag: copy failed for user space data\n");
+			return -EIO;
+		}
+		/* Check for proc_type */
+		remote_proc = diag_get_remote(*(int *)driver->user_space_data);
+
+		if (!remote_proc) {
+			wait_event_interruptible(driver->wait_q,
+				 (driver->in_busy_pktdata == 0));
+			return diag_process_apps_pkt(driver->user_space_data,
+							payload_size);
+		}
+		/* The packet is for the remote processor */
+		token_offset = 4;
+		payload_size -= 4;
+		buf += 4;
+		/* Perform HDLC encoding on incoming data */
+		send.state = DIAG_STATE_START;
+		send.pkt = (void *)(driver->user_space_data + token_offset);
+		send.last = (void *)(driver->user_space_data + token_offset -
+							1 + payload_size);
+		send.terminate = 1;
+
+		mutex_lock(&driver->diagchar_mutex);
+		if (!buf_hdlc)
+			buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
+							POOL_TYPE_HDLC);
+		if (!buf_hdlc) {
+			ret = -ENOMEM;
+			goto fail_free_hdlc;
+		}
+		if (HDLC_OUT_BUF_SIZE < (2 * payload_size) + 3) {
+			pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
+					((2*payload_size) + 3));
+			driver->dropped_count++;
+			ret = -EBADMSG;
+			diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+			goto fail_free_hdlc;
+		}
+		enc.dest = buf_hdlc + driver->used;
+		enc.dest_last = (void *)(buf_hdlc + driver->used +
+					(2 * payload_size) + token_offset - 1);
+		diag_hdlc_encode(&send, &enc);
+
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		/* send masks to 9k too */
+		if (driver->sdio_ch && (remote_proc == MDM)) {
+			wait_event_interruptible(driver->wait_q,
+				 (sdio_write_avail(driver->sdio_ch) >=
+					 payload_size));
+			if (driver->sdio_ch && (payload_size > 0)) {
+				sdio_write(driver->sdio_ch, (void *)
+				   (char *)buf_hdlc, payload_size + 3);
+			}
+		}
+#endif
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+		/* send masks to All 9k */
+		if ((remote_proc >= MDM) && (remote_proc <= MDM4)) {
+			index = remote_proc - MDM;
+			if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
+				/* wait sending mask updates
+				 * if HSIC ch not ready */
+				if (diag_hsic[index].in_busy_hsic_write)
+					wait_event_interruptible(driver->wait_q,
+						(diag_hsic[index].
+						 in_busy_hsic_write != 1));
+				diag_hsic[index].in_busy_hsic_write = 1;
+				diag_hsic[index].in_busy_hsic_read_on_device =
+									0;
+				err = diag_bridge_write(index,
+					(char *)buf_hdlc, payload_size + 3);
+				if (err) {
+					pr_err("diag: err sending mask to MDM: %d\n",
+					       err);
+					/*
+					* If the error is recoverable, then
+					* clear the write flag, so we will
+					* resubmit a write on the next frame.
+					* Otherwise, don't resubmit a write
+					* on the next frame.
+					*/
+					if ((-ESHUTDOWN) != err)
+						diag_hsic[index].
+							in_busy_hsic_write = 0;
+				 }
+			 }
+		}
+		if (driver->diag_smux_enabled && (remote_proc == QSC)
+						&& driver->lcid) {
+			if (payload_size > 0) {
+				err = msm_smux_write(driver->lcid, NULL,
+					(char *)buf_hdlc, payload_size + 3);
+				if (err) {
+					pr_err("diag:send mask to MDM err %d",
+							err);
+					ret = err;
+				}
+			}
+		}
+#endif
+		diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
+		buf_hdlc = NULL;
+		driver->used = 0;
+		mutex_unlock(&driver->diagchar_mutex);
+		return ret;
+	}
 	if (pkt_type == USER_SPACE_DATA_TYPE) {
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
@@ -1839,6 +1951,7 @@
 		driver->socket_process = NULL;
 		driver->callback_process = NULL;
 		driver->mask_check = 0;
+		driver->in_busy_pktdata = 0;
 		mutex_init(&driver->diagchar_mutex);
 		init_waitqueue_head(&driver->wait_q);
 		init_waitqueue_head(&driver->smd_wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index bb74370..5b929d7 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -641,9 +641,10 @@
 	unsigned char *temp = buf;
 
 	mutex_lock(&driver->diagchar_mutex);
-	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length))
+	if (CHK_OVERFLOW(ptr, ptr, ptr + PKT_SIZE, driver->pkt_length)) {
 		memcpy(ptr, temp , driver->pkt_length);
-	else
+		driver->in_busy_pktdata = 1;
+	} else
 		printk(KERN_CRIT " Not enough buffer space for PKT_RESP\n");
 	mutex_unlock(&driver->diagchar_mutex);
 }
@@ -718,7 +719,7 @@
 	}
 }
 
-static int diag_process_apps_pkt(unsigned char *buf, int len)
+int diag_process_apps_pkt(unsigned char *buf, int len)
 {
 	uint16_t subsys_cmd_code;
 	int subsys_id, ssid_first, ssid_last, ssid_range;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 8cf15de..09f2f5e 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -48,6 +48,7 @@
 int diag_command_reg(unsigned long);
 void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
 void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
+int diag_process_apps_pkt(unsigned char *buf, int len);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 4ddd78a..c3ff7dc 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -86,14 +86,15 @@
 			range = buf+HDR_SIZ+
 					sizeof(struct diag_ctrl_msg);
 			pkt_params->count = msg->count_entries;
-			temp = kzalloc(pkt_params->count * sizeof(struct
-					 bindpkt_params), GFP_KERNEL);
-			if (temp == NULL) {
+			pkt_params->params = kzalloc(pkt_params->count *
+				sizeof(struct bindpkt_params), GFP_KERNEL);
+			if (pkt_params->params == NULL) {
 				pr_alert("diag: In %s, Memory alloc fail\n",
 					__func__);
 				kfree(pkt_params);
 				return flag;
 			}
+			temp = pkt_params->params;
 			for (j = 0; j < pkt_params->count; j++) {
 				temp->cmd_code = msg->cmd_code;
 				temp->subsys_id = msg->subsysid;
@@ -104,8 +105,6 @@
 				range++;
 				temp++;
 			}
-			temp -= pkt_params->count;
-			pkt_params->params = temp;
 			flag = 1;
 			/* peripheral undergoing SSR should not
 			 * record new registration
@@ -116,7 +115,7 @@
 			else
 				pr_err("diag: drop reg proc %d\n",
 						smd_info->peripheral);
-			kfree(temp);
+			kfree(pkt_params->params);
 		} else if ((type == DIAG_CTRL_MSG_FEATURE) &&
 				(smd_info->peripheral == MODEM_DATA)) {
 			feature_mask_len = *(int *)(buf + 8);
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 9128177..85e2ec9 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -39,7 +39,6 @@
 
 #include <mach/iommu_domains.h>
 #include "ion_priv.h"
-#define DEBUG
 
 /**
  * struct ion_device - the metadata of the ion device node
@@ -107,6 +106,12 @@
 	unsigned int iommu_map_cnt;
 };
 
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
+{
+        return ((buffer->flags & ION_FLAG_CACHED) &&
+                !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
+}
+
 static void ion_iommu_release(struct kref *kref);
 
 /* this function should only be called while dev->lock is held */
@@ -190,6 +195,8 @@
 	return NULL;
 }
 
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
+
 /* this function should only be called while dev->lock is held */
 static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 				     struct ion_device *dev,
@@ -199,13 +206,15 @@
 {
 	struct ion_buffer *buffer;
 	struct sg_table *table;
-	int ret;
+	struct scatterlist *sg;
+	int i, ret;
 
 	buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
 	if (!buffer)
 		return ERR_PTR(-ENOMEM);
 
 	buffer->heap = heap;
+	buffer->flags = flags;
 	kref_init(&buffer->ref);
 
 	ret = heap->ops->allocate(heap, buffer, len, align, flags);
@@ -216,19 +225,52 @@
 
 	buffer->dev = dev;
 	buffer->size = len;
-	buffer->flags = flags;
 
-	table = buffer->heap->ops->map_dma(buffer->heap, buffer);
+	table = heap->ops->map_dma(heap, buffer);
 	if (IS_ERR_OR_NULL(table)) {
 		heap->ops->free(buffer);
 		kfree(buffer);
 		return ERR_PTR(PTR_ERR(table));
 	}
 	buffer->sg_table = table;
+	if (ion_buffer_fault_user_mappings(buffer)) {
+		for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents,
+			    i) {
+			if (sg_dma_len(sg) == PAGE_SIZE)
+				continue;
+			pr_err("%s: cached mappings that will be faulted in "
+			       "must have pagewise sg_lists\n", __func__);
+			ret = -EINVAL;
+			goto err;
+		}
 
+		ret = ion_buffer_alloc_dirty(buffer);
+		if (ret)
+			goto err;
+	}
+
+	buffer->dev = dev;
+	buffer->size = len;
+	INIT_LIST_HEAD(&buffer->vmas);
 	mutex_init(&buffer->lock);
+	/* this will set up dma addresses for the sglist -- it is not
+	   technically correct as per the dma api -- a specific
+	   device isn't really taking ownership here.  However, in practice on
+	   our systems the only dma_address space is physical addresses.
+	   Additionally, we can't afford the overhead of invalidating every
+	   allocation via dma_map_sg. The implicit contract here is that
+	   memory comming from the heaps is ready for dma, ie if it has a
+	   cached mapping that mapping has been invalidated */
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
+		sg_dma_address(sg) = sg_phys(sg);
 	ion_buffer_add(dev, buffer);
 	return buffer;
+
+err:
+	heap->ops->unmap_dma(heap, buffer);
+	heap->ops->free(buffer);
+	kfree(buffer);
+	return ERR_PTR(ret);
 }
 
 /**
@@ -276,7 +318,6 @@
 
 	if (WARN_ON(buffer->kmap_cnt > 0))
 		buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
-
 	buffer->heap->ops->unmap_dma(buffer->heap, buffer);
 
 	ion_delayed_unsecure(buffer);
@@ -285,6 +326,8 @@
 	mutex_lock(&dev->lock);
 	rb_erase(&buffer->node, &dev->buffers);
 	mutex_unlock(&dev->lock);
+	if (buffer->flags & ION_FLAG_CACHED)
+		kfree(buffer->dirty);
 	kfree(buffer);
 }
 
@@ -419,6 +462,16 @@
 	dbg_str[0] = '\0';
 
 	/*
+	 * For now, we don't want to fault in pages individually since
+	 * clients are already doing manual cache maintenance. In
+	 * other words, the implicit caching infrastructure is in
+	 * place (in code) but should not be used.
+	 */
+	flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
+	pr_debug("%s: len %d align %d heap_mask %u flags %x\n", __func__, len,
+		 align, heap_mask, flags);
+	/*
 	 * traverse the list of heaps available in this system in priority
 	 * order.  If the heap type is supported by the client, and matches the
 	 * request of the caller allocate from it.  Repeat until allocate has
@@ -1205,12 +1258,46 @@
 }
 EXPORT_SYMBOL(ion_sg_table);
 
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+					size_t chunk_size, size_t total_size)
+{
+	struct sg_table *table;
+	int i, n_chunks, ret;
+	struct scatterlist *sg;
+
+	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table)
+		return ERR_PTR(-ENOMEM);
+
+	n_chunks = DIV_ROUND_UP(total_size, chunk_size);
+	pr_debug("creating sg_table with %d chunks\n", n_chunks);
+
+	ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
+	if (ret)
+		goto err0;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		dma_addr_t addr = buffer_base + i * chunk_size;
+		sg_dma_address(sg) = addr;
+	}
+
+	return table;
+err0:
+	kfree(table);
+	return ERR_PTR(ret);
+}
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+				       struct device *dev,
+				       enum dma_data_direction direction);
+
 static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
 					enum dma_data_direction direction)
 {
 	struct dma_buf *dmabuf = attachment->dmabuf;
 	struct ion_buffer *buffer = dmabuf->priv;
 
+	ion_buffer_sync_for_device(buffer, attachment->dev, direction);
 	return buffer->sg_table;
 }
 
@@ -1220,24 +1307,119 @@
 {
 }
 
-static void ion_vma_close(struct vm_area_struct *vma)
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer)
+{
+	unsigned long pages = buffer->sg_table->nents;
+	unsigned long length = (pages + BITS_PER_LONG - 1)/BITS_PER_LONG;
+
+	buffer->dirty = kzalloc(length * sizeof(unsigned long), GFP_KERNEL);
+	if (!buffer->dirty)
+		return -ENOMEM;
+	return 0;
+}
+
+struct ion_vma_list {
+	struct list_head list;
+	struct vm_area_struct *vma;
+};
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+				       struct device *dev,
+				       enum dma_data_direction dir)
+{
+	struct scatterlist *sg;
+	int i;
+	struct ion_vma_list *vma_list;
+
+	pr_debug("%s: syncing for device %s\n", __func__,
+		 dev ? dev_name(dev) : "null");
+
+	if (!ion_buffer_fault_user_mappings(buffer))
+		return;
+
+	mutex_lock(&buffer->lock);
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+		if (!test_bit(i, buffer->dirty))
+			continue;
+		dma_sync_sg_for_device(dev, sg, 1, dir);
+		clear_bit(i, buffer->dirty);
+	}
+	list_for_each_entry(vma_list, &buffer->vmas, list) {
+		struct vm_area_struct *vma = vma_list->vma;
+
+		zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start,
+			       NULL);
+	}
+	mutex_unlock(&buffer->lock);
+}
+
+int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct ion_buffer *buffer = vma->vm_private_data;
+	struct scatterlist *sg;
+	int i;
 
-	pr_debug("%s: %d\n", __func__, __LINE__);
+	mutex_lock(&buffer->lock);
+	set_bit(vmf->pgoff, buffer->dirty);
+
+	for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+		if (i != vmf->pgoff)
+			continue;
+		dma_sync_sg_for_cpu(NULL, sg, 1, DMA_BIDIRECTIONAL);
+		vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+			       sg_page(sg));
+		break;
+	}
+	mutex_unlock(&buffer->lock);
+	return VM_FAULT_NOPAGE;
+}
+
+static void ion_vm_open(struct vm_area_struct *vma)
+{
+	struct ion_buffer *buffer = vma->vm_private_data;
+	struct ion_vma_list *vma_list;
+
+	vma_list = kmalloc(sizeof(struct ion_vma_list), GFP_KERNEL);
+	if (!vma_list)
+		return;
+	vma_list->vma = vma;
+	mutex_lock(&buffer->lock);
+	list_add(&vma_list->list, &buffer->vmas);
+	mutex_unlock(&buffer->lock);
+	pr_debug("%s: adding %p\n", __func__, vma);
+}
+
+static void ion_vm_close(struct vm_area_struct *vma)
+{
+	struct ion_buffer *buffer = vma->vm_private_data;
+	struct ion_vma_list *vma_list, *tmp;
+
+	pr_debug("%s\n", __func__);
+	mutex_lock(&buffer->lock);
+	list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) {
+		if (vma_list->vma != vma)
+			continue;
+		list_del(&vma_list->list);
+		kfree(vma_list);
+		pr_debug("%s: deleting %p\n", __func__, vma);
+		break;
+	}
+	mutex_unlock(&buffer->lock);
 
 	if (buffer->heap->ops->unmap_user)
 		buffer->heap->ops->unmap_user(buffer->heap, buffer);
 }
 
-static struct vm_operations_struct ion_vm_ops = {
-	.close = ion_vma_close,
+struct vm_operations_struct ion_vma_ops = {
+	.open = ion_vm_open,
+	.close = ion_vm_close,
+	.fault = ion_vm_fault,
 };
 
 static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
 {
 	struct ion_buffer *buffer = dmabuf->priv;
-	int ret;
+	int ret = 0;
 
 	if (!buffer->heap->ops->map_user) {
 		pr_err("%s: this heap does not define a method for mapping "
@@ -1245,22 +1427,26 @@
 		return -EINVAL;
 	}
 
+	if (ion_buffer_fault_user_mappings(buffer)) {
+		vma->vm_private_data = buffer;
+		vma->vm_ops = &ion_vma_ops;
+		vma->vm_flags |= VM_MIXEDMAP;
+		ion_vm_open(vma);
+		return 0;
+	}
+
+	if (!(buffer->flags & ION_FLAG_CACHED))
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
 	mutex_lock(&buffer->lock);
 	/* now map it to userspace */
 	ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
 	mutex_unlock(&buffer->lock);
 
-	if (ret) {
+	if (ret)
 		pr_err("%s: failure mapping buffer to userspace\n",
 		       __func__);
-	} else {
-		vma->vm_ops = &ion_vm_ops;
-		/*
-		 * move the buffer into the vm_private_data so we can access it
-		 * from vma_open/close
-		 */
-		vma->vm_private_data = buffer;
-	}
+
 	return ret;
 }
 
@@ -1396,6 +1582,30 @@
 }
 EXPORT_SYMBOL(ion_import_dma_buf);
 
+static int ion_sync_for_device(struct ion_client *client, int fd)
+{
+	struct dma_buf *dmabuf;
+	struct ion_buffer *buffer;
+
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR_OR_NULL(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	/* if this memory came from ion */
+	if (dmabuf->ops != &dma_buf_ops) {
+		pr_err("%s: can not sync dmabuf from another exporter\n",
+		       __func__);
+		dma_buf_put(dmabuf);
+		return -EINVAL;
+	}
+	buffer = dmabuf->priv;
+
+	dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
+			       buffer->sg_table->nents, DMA_BIDIRECTIONAL);
+	dma_buf_put(dmabuf);
+	return 0;
+}
+
 static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct ion_client *client = filp->private_data;
@@ -1468,6 +1678,15 @@
 			return ret;
 		break;
 	}
+	case ION_IOC_SYNC:
+	{
+		struct ion_fd_data data;
+		if (copy_from_user(&data, (void __user *)arg,
+				   sizeof(struct ion_fd_data)))
+			return -EFAULT;
+		ion_sync_for_device(client, data.fd);
+		break;
+	}
 	case ION_IOC_CUSTOM:
 	{
 		struct ion_device *dev = client->dev;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 798c027..9610dfe 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -112,26 +112,13 @@
 struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
 					      struct ion_buffer *buffer)
 {
-	struct sg_table *table;
-	int ret;
+	size_t chunk_size = buffer->size;
 
-	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!table)
-		return ERR_PTR(-ENOMEM);
+	if (ION_IS_CACHED(buffer->flags))
+		chunk_size = PAGE_SIZE;
 
-	ret = sg_alloc_table(table, 1, GFP_KERNEL);
-	if (ret)
-		goto err0;
-
-	table->sgl->length = buffer->size;
-	table->sgl->offset = 0;
-	table->sgl->dma_address = buffer->priv_phys;
-
-	return table;
-
-err0:
-	kfree(table);
-	return ERR_PTR(ret);
+	return ion_create_chunked_sg_table(buffer->priv_phys, chunk_size,
+					buffer->size);
 }
 
 void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 8a5e5c9..2ef285b 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -457,6 +457,12 @@
 	struct ion_cp_buffer *buf;
 	phys_addr_t addr;
 
+	/*
+	 * we never want Ion to fault pages in for us with this
+	 * heap. We want to set up the mappings ourselves in .map_user
+	 */
+	flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 	if (!buf)
 		return ION_CP_ALLOCATE_FAIL;
@@ -491,9 +497,6 @@
 struct sg_table *ion_cp_heap_create_sg_table(struct ion_buffer *buffer)
 {
 	size_t chunk_size = buffer->size;
-	struct sg_table *table;
-	int ret, i, n_chunks;
-	struct scatterlist *sg;
 	struct ion_cp_buffer *buf = buffer->priv_virt;
 
 	if (ION_IS_CACHED(buffer->flags))
@@ -501,26 +504,8 @@
 	else if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M))
 		chunk_size = SZ_1M;
 
-	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!table)
-		return ERR_PTR(-ENOMEM);
-
-	n_chunks = DIV_ROUND_UP(buffer->size, chunk_size);
-
-	ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
-	if (ret)
-		goto err0;
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		sg_dma_address(sg) = buf->buffer + i * chunk_size;
-		sg->length = chunk_size;
-		sg->offset = 0;
-	}
-
-	return table;
-err0:
-	kfree(table);
-	return ERR_PTR(ret);
+	return ion_create_chunked_sg_table(buf->buffer, chunk_size,
+					buffer->size);
 }
 
 struct sg_table *ion_cp_heap_map_dma(struct ion_heap *heap,
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 2ab2ed6..28ef1a5 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -98,6 +98,8 @@
 	void *vaddr;
 	int dmap_cnt;
 	struct sg_table *sg_table;
+	unsigned long *dirty;
+	struct list_head vmas;
 	unsigned int iommu_map_cnt;
 	struct rb_root iommu_maps;
 	int marked;
@@ -179,6 +181,15 @@
 };
 
 /**
+ * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
+ * @buffer:		buffer
+ *
+ * indicates whether userspace mappings of this buffer will be faulted
+ * in, this can affect how buffers are allocated from the heap.
+ */
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer);
+
+/**
  * struct mem_map_data - represents information about the memory map for a heap
  * @node:		rb node used to store in the tree of mem_map_data
  * @addr:		start address of memory region.
@@ -330,4 +341,16 @@
 int ion_heap_allow_heap_secure(enum ion_heap_type type);
 
 int ion_heap_allow_handle_secure(enum ion_heap_type type);
+
+/**
+ * ion_create_chunked_sg_table - helper function to create sg table
+ * with specified chunk size
+ * @buffer_base:	The starting address used for the sg dma address
+ * @chunk_size:		The size of each entry in the sg table
+ * @total_size:		The total size of the sg table (i.e. the sum of the
+ *			entries). This will be rounded up to the nearest
+ *			multiple of `chunk_size'
+ */
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+					size_t chunk_size, size_t total_size);
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 7046709..ceb30a4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -15,7 +15,10 @@
  *
  */
 
+#include <asm/page.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
+#include <linux/highmem.h>
 #include <linux/ion.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
@@ -35,6 +38,37 @@
 static unsigned int system_heap_has_outer_cache;
 static unsigned int system_heap_contig_has_outer_cache;
 
+struct page_info {
+	struct page *page;
+	unsigned long order;
+	struct list_head list;
+};
+
+static struct page_info *alloc_largest_available(unsigned long size,
+						 bool split_pages)
+{
+	static unsigned int orders[] = {8, 4, 0};
+	struct page *page;
+	struct page_info *info;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(orders); i++) {
+		if (size < (1 << orders[i]) * PAGE_SIZE)
+			continue;
+		page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO |
+				   __GFP_NOWARN | __GFP_NORETRY, orders[i]);
+		if (!page)
+			continue;
+		if (split_pages)
+			split_page(page, orders[i]);
+		info = kmap(page);
+		info->page = page;
+		info->order = orders[i];
+		return info;
+	}
+	return NULL;
+}
+
 static int ion_system_heap_allocate(struct ion_heap *heap,
 				     struct ion_buffer *buffer,
 				     unsigned long size, unsigned long align,
@@ -42,31 +76,73 @@
 {
 	struct sg_table *table;
 	struct scatterlist *sg;
-	int i, j;
-	int npages = PAGE_ALIGN(size) / PAGE_SIZE;
+	int ret;
+	struct list_head pages;
+	struct page_info *info, *tmp_info;
+	int i = 0;
+	long size_remaining = PAGE_ALIGN(size);
+	bool split_pages = ion_buffer_fault_user_mappings(buffer);
+
+
+	INIT_LIST_HEAD(&pages);
+	while (size_remaining > 0) {
+		info = alloc_largest_available(size_remaining, split_pages);
+		if (!info)
+			goto err;
+		list_add_tail(&info->list, &pages);
+		size_remaining -= (1 << info->order) * PAGE_SIZE;
+		i++;
+	}
 
 	table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
 	if (!table)
-		return -ENOMEM;
-	i = sg_alloc_table(table, npages, GFP_KERNEL);
-	if (i)
-		goto err0;
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		struct page *page;
-		page = alloc_page(GFP_KERNEL|__GFP_ZERO);
-		if (!page)
-			goto err1;
-		sg_set_page(sg, page, PAGE_SIZE, 0);
+		goto err;
+
+	if (split_pages)
+		ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE,
+				     GFP_KERNEL);
+	else
+		ret = sg_alloc_table(table, i, GFP_KERNEL);
+
+	if (ret)
+		goto err1;
+
+	sg = table->sgl;
+	list_for_each_entry_safe(info, tmp_info, &pages, list) {
+		struct page *page = info->page;
+
+		if (split_pages) {
+			for (i = 0; i < (1 << info->order); i++) {
+				sg_set_page(sg, page + i, PAGE_SIZE, 0);
+				sg = sg_next(sg);
+			}
+		} else {
+			sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE,
+				    0);
+			sg = sg_next(sg);
+		}
+		list_del(&info->list);
+		kunmap(page);
 	}
+
+	dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+			       DMA_BIDIRECTIONAL);
+
 	buffer->priv_virt = table;
 	atomic_add(size, &system_heap_allocated);
 	return 0;
 err1:
-	for_each_sg(table->sgl, sg, i, j)
-		__free_page(sg_page(sg));
-	sg_free_table(table);
-err0:
 	kfree(table);
+err:
+	list_for_each_entry(info, &pages, list) {
+		if (split_pages)
+			for (i = 0; i < (1 << info->order); i++)
+				__free_page(info->page + i);
+		else
+			__free_pages(info->page, info->order);
+
+		kunmap(info->page);
+	}
 	return -ENOMEM;
 }
 
@@ -77,7 +153,7 @@
 	struct sg_table *table = buffer->priv_virt;
 
 	for_each_sg(table->sgl, sg, table->nents, i)
-		__free_page(sg_page(sg));
+		__free_pages(sg_page(sg), get_order(sg_dma_len(sg)));
 	if (buffer->sg_table)
 		sg_free_table(buffer->sg_table);
 	kfree(buffer->sg_table);
@@ -99,25 +175,33 @@
 void *ion_system_heap_map_kernel(struct ion_heap *heap,
 				 struct ion_buffer *buffer)
 {
-	if (!ION_IS_CACHED(buffer->flags)) {
-		pr_err("%s: cannot map system heap uncached\n", __func__);
-		return ERR_PTR(-EINVAL);
-	} else {
-		struct scatterlist *sg;
-		int i;
-		void *vaddr;
-		struct sg_table *table = buffer->priv_virt;
-		struct page **pages = kmalloc(
-					sizeof(struct page *) * table->nents,
-					GFP_KERNEL);
+	struct scatterlist *sg;
+	int i, j;
+	void *vaddr;
+	pgprot_t pgprot;
+	struct sg_table *table = buffer->priv_virt;
+	int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+	struct page **pages = kzalloc(sizeof(struct page *) * npages,
+				     GFP_KERNEL);
+	struct page **tmp = pages;
 
-		for_each_sg(table->sgl, sg, table->nents, i)
-			pages[i] = sg_page(sg);
-		vaddr = vmap(pages, table->nents, VM_MAP, PAGE_KERNEL);
-		kfree(pages);
+	if (buffer->flags & ION_FLAG_CACHED)
+		pgprot = PAGE_KERNEL;
+	else
+		pgprot = pgprot_writecombine(PAGE_KERNEL);
 
-		return vaddr;
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
+		struct page *page = sg_page(sg);
+		BUG_ON(i >= npages);
+		for (j = 0; j < npages_this_entry; j++) {
+			*(tmp++) = page++;
+		}
 	}
+	vaddr = vmap(pages, npages, VM_MAP, pgprot);
+	kfree(pages);
+
+	return vaddr;
 }
 
 void ion_system_heap_unmap_kernel(struct ion_heap *heap,
@@ -155,26 +239,27 @@
 int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 			     struct vm_area_struct *vma)
 {
+	struct sg_table *table = buffer->priv_virt;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff;
+	struct scatterlist *sg;
+	int i;
+
 	if (!ION_IS_CACHED(buffer->flags)) {
 		pr_err("%s: cannot map system heap uncached\n", __func__);
 		return -EINVAL;
-	} else {
-		struct sg_table *table = buffer->priv_virt;
-		unsigned long addr = vma->vm_start;
-		unsigned long offset = vma->vm_pgoff;
-		struct scatterlist *sg;
-		int i;
-
-		for_each_sg(table->sgl, sg, table->nents, i) {
-			if (offset) {
-				offset--;
-				continue;
-			}
-			vm_insert_page(vma, addr, sg_page(sg));
-			addr += PAGE_SIZE;
-		}
-		return 0;
 	}
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		if (offset) {
+			offset--;
+			continue;
+		}
+		remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)),
+				sg_dma_len(sg), vma->vm_page_prot);
+		addr += sg_dma_len(sg);
+	}
+	return 0;
 }
 
 int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -382,7 +467,7 @@
 }
 
 struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
-						   struct ion_buffer *buffer)
+						struct ion_buffer *buffer)
 {
 	struct sg_table *table;
 	int ret;
@@ -400,6 +485,13 @@
 	return table;
 }
 
+void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
+				      struct ion_buffer *buffer)
+{
+	sg_free_table(buffer->sg_table);
+	kfree(buffer->sg_table);
+}
+
 int ion_system_contig_heap_map_user(struct ion_heap *heap,
 				    struct ion_buffer *buffer,
 				    struct vm_area_struct *vma)
@@ -561,7 +653,7 @@
 	.free = ion_system_contig_heap_free,
 	.phys = ion_system_contig_heap_phys,
 	.map_dma = ion_system_contig_heap_map_dma,
-	.unmap_dma = ion_system_heap_unmap_dma,
+	.unmap_dma = ion_system_contig_heap_unmap_dma,
 	.map_kernel = ion_system_contig_heap_map_kernel,
 	.unmap_kernel = ion_system_contig_heap_unmap_kernel,
 	.map_user = ion_system_contig_heap_map_user,
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index ed351bd..05c70a7 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -66,15 +66,103 @@
 #define A3XX_RBBM_INT_0_MASK 0x063
 #define A3XX_RBBM_INT_0_STATUS 0x064
 #define A3XX_RBBM_PERFCTR_CTL 0x80
+#define A3XX_RBBM_PERFCTR_LOAD_CMD0 0x81
+#define A3XX_RBBM_PERFCTR_LOAD_CMD1 0x82
+#define A3XX_RBBM_PERFCTR_LOAD_VALUE_LO 0x84
+#define A3XX_RBBM_PERFCTR_LOAD_VALUE_HI 0x85
+#define A3XX_RBBM_PERFCOUNTER0_SELECT 0x86
+#define A3XX_RBBM_PERFCOUNTER1_SELECT 0x87
 #define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_CP_0_LO 0x90
+#define A3XX_RBBM_PERFCTR_CP_0_HI 0x91
+#define A3XX_RBBM_PERFCTR_RBBM_0_LO 0x92
+#define A3XX_RBBM_PERFCTR_RBBM_0_HI 0x93
+#define A3XX_RBBM_PERFCTR_RBBM_1_LO 0x94
+#define A3XX_RBBM_PERFCTR_RBBM_1_HI 0x95
+#define A3XX_RBBM_PERFCTR_PC_0_LO 0x96
+#define A3XX_RBBM_PERFCTR_PC_0_HI 0x97
+#define A3XX_RBBM_PERFCTR_PC_1_LO 0x98
+#define A3XX_RBBM_PERFCTR_PC_1_HI 0x99
+#define A3XX_RBBM_PERFCTR_PC_2_LO 0x9A
+#define A3XX_RBBM_PERFCTR_PC_2_HI 0x9B
+#define A3XX_RBBM_PERFCTR_PC_3_LO 0x9C
+#define A3XX_RBBM_PERFCTR_PC_3_HI 0x9D
+#define A3XX_RBBM_PERFCTR_VFD_0_LO 0x9E
+#define A3XX_RBBM_PERFCTR_VFD_0_HI 0x9F
+#define A3XX_RBBM_PERFCTR_VFD_1_LO 0xA0
+#define A3XX_RBBM_PERFCTR_VFD_1_HI 0xA1
+#define A3XX_RBBM_PERFCTR_HLSQ_0_LO 0xA2
+#define A3XX_RBBM_PERFCTR_HLSQ_0_HI 0xA3
+#define A3XX_RBBM_PERFCTR_HLSQ_1_LO 0xA4
+#define A3XX_RBBM_PERFCTR_HLSQ_1_HI 0xA5
+#define A3XX_RBBM_PERFCTR_HLSQ_2_LO 0xA6
+#define A3XX_RBBM_PERFCTR_HLSQ_2_HI 0xA7
+#define A3XX_RBBM_PERFCTR_HLSQ_3_LO 0xA8
+#define A3XX_RBBM_PERFCTR_HLSQ_3_HI 0xA9
+#define A3XX_RBBM_PERFCTR_HLSQ_4_LO 0xAA
+#define A3XX_RBBM_PERFCTR_HLSQ_4_HI 0xAB
+#define A3XX_RBBM_PERFCTR_HLSQ_5_LO 0xAC
+#define A3XX_RBBM_PERFCTR_HLSQ_5_HI 0xAD
+#define A3XX_RBBM_PERFCTR_VPC_0_LO 0xAE
+#define A3XX_RBBM_PERFCTR_VPC_0_HI 0xAF
+#define A3XX_RBBM_PERFCTR_VPC_1_LO 0xB0
+#define A3XX_RBBM_PERFCTR_VPC_1_HI 0xB1
+#define A3XX_RBBM_PERFCTR_TSE_0_LO 0xB2
+#define A3XX_RBBM_PERFCTR_TSE_0_HI 0xB3
+#define A3XX_RBBM_PERFCTR_TSE_1_LO 0xB4
+#define A3XX_RBBM_PERFCTR_TSE_1_HI 0xB5
+#define A3XX_RBBM_PERFCTR_RAS_0_LO 0xB6
+#define A3XX_RBBM_PERFCTR_RAS_0_HI 0xB7
+#define A3XX_RBBM_PERFCTR_RAS_1_LO 0xB8
+#define A3XX_RBBM_PERFCTR_RAS_1_HI 0xB9
+#define A3XX_RBBM_PERFCTR_UCHE_0_LO 0xBA
+#define A3XX_RBBM_PERFCTR_UCHE_0_HI 0xBB
+#define A3XX_RBBM_PERFCTR_UCHE_1_LO 0xBC
+#define A3XX_RBBM_PERFCTR_UCHE_1_HI 0xBD
+#define A3XX_RBBM_PERFCTR_UCHE_2_LO 0xBE
+#define A3XX_RBBM_PERFCTR_UCHE_2_HI 0xBF
+#define A3XX_RBBM_PERFCTR_UCHE_3_LO 0xC0
+#define A3XX_RBBM_PERFCTR_UCHE_3_HI 0xC1
+#define A3XX_RBBM_PERFCTR_UCHE_4_LO 0xC2
+#define A3XX_RBBM_PERFCTR_UCHE_4_HI 0xC3
+#define A3XX_RBBM_PERFCTR_UCHE_5_LO 0xC4
+#define A3XX_RBBM_PERFCTR_UCHE_5_HI 0xC5
+#define A3XX_RBBM_PERFCTR_TP_0_LO 0xC6
+#define A3XX_RBBM_PERFCTR_TP_0_HI 0xC7
+#define A3XX_RBBM_PERFCTR_TP_1_LO 0xC8
+#define A3XX_RBBM_PERFCTR_TP_1_HI 0xC9
+#define A3XX_RBBM_PERFCTR_TP_2_LO 0xCA
+#define A3XX_RBBM_PERFCTR_TP_2_HI 0xCB
+#define A3XX_RBBM_PERFCTR_TP_3_LO 0xCC
+#define A3XX_RBBM_PERFCTR_TP_3_HI 0xCD
+#define A3XX_RBBM_PERFCTR_TP_4_LO 0xCE
+#define A3XX_RBBM_PERFCTR_TP_4_HI 0xCF
+#define A3XX_RBBM_PERFCTR_TP_5_LO 0xD0
+#define A3XX_RBBM_PERFCTR_TP_5_HI 0xD1
+#define A3XX_RBBM_PERFCTR_SP_0_LO 0xD2
+#define A3XX_RBBM_PERFCTR_SP_0_HI 0xD3
+#define A3XX_RBBM_PERFCTR_SP_1_LO 0xD4
+#define A3XX_RBBM_PERFCTR_SP_1_HI 0xD5
+#define A3XX_RBBM_PERFCTR_SP_2_LO 0xD6
+#define A3XX_RBBM_PERFCTR_SP_2_HI 0xD7
+#define A3XX_RBBM_PERFCTR_SP_3_LO 0xD8
+#define A3XX_RBBM_PERFCTR_SP_3_HI 0xD9
+#define A3XX_RBBM_PERFCTR_SP_4_LO 0xDA
+#define A3XX_RBBM_PERFCTR_SP_4_HI 0xDB
 #define A3XX_RBBM_PERFCTR_SP_5_LO 0xDC
 #define A3XX_RBBM_PERFCTR_SP_5_HI 0xDD
 #define A3XX_RBBM_PERFCTR_SP_6_LO 0xDE
 #define A3XX_RBBM_PERFCTR_SP_6_HI 0xDF
 #define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
 #define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
+#define A3XX_RBBM_PERFCTR_RB_0_LO 0xE2
+#define A3XX_RBBM_PERFCTR_RB_0_HI 0xE3
+#define A3XX_RBBM_PERFCTR_RB_1_LO 0xE4
+#define A3XX_RBBM_PERFCTR_RB_1_HI 0xE5
+
 #define A3XX_RBBM_RBBM_CTL 0x100
-#define A3XX_RBBM_RBBM_CTL 0x100
+#define A3XX_RBBM_PERFCTR_PWR_0_LO 0x0EA
+#define A3XX_RBBM_PERFCTR_PWR_0_HI 0x0EB
 #define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
 #define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
 #define A3XX_RBBM_DEBUG_BUS_CTL             0x111
@@ -90,6 +178,7 @@
 #define A3XX_CP_MERCIU_DATA2 0x1D3
 #define A3XX_CP_MEQ_ADDR 0x1DA
 #define A3XX_CP_MEQ_DATA 0x1DB
+#define A3XX_CP_PERFCOUNTER_SELECT 0x445
 #define A3XX_CP_HW_FAULT  0x45C
 #define A3XX_CP_AHB_FAULT 0x54D
 #define A3XX_CP_PROTECT_CTRL 0x45E
@@ -138,6 +227,14 @@
 #define A3XX_VSC_PIPE_CONFIG_7 0xC1B
 #define A3XX_VSC_PIPE_DATA_ADDRESS_7 0xC1C
 #define A3XX_VSC_PIPE_DATA_LENGTH_7 0xC1D
+#define A3XX_PC_PERFCOUNTER0_SELECT 0xC48
+#define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
+#define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
+#define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
+#define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
+#define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
+#define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
+#define A3XX_GRAS_PERFCOUNTER3_SELECT 0xC8B
 #define A3XX_GRAS_CL_USER_PLANE_X0 0xCA0
 #define A3XX_GRAS_CL_USER_PLANE_Y0 0xCA1
 #define A3XX_GRAS_CL_USER_PLANE_Z0 0xCA2
@@ -163,14 +260,42 @@
 #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
 #define A3XX_RB_GMEM_BASE_ADDR 0xCC0
+#define A3XX_RB_PERFCOUNTER0_SELECT   0xCC6
+#define A3XX_RB_PERFCOUNTER1_SELECT   0xCC7
+#define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00
+#define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01
+#define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02
+#define A3XX_HLSQ_PERFCOUNTER3_SELECT 0xE03
+#define A3XX_HLSQ_PERFCOUNTER4_SELECT 0xE04
+#define A3XX_HLSQ_PERFCOUNTER5_SELECT 0xE05
 #define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
+#define A3XX_VFD_PERFCOUNTER1_SELECT 0xE45
 #define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
 #define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
+#define A3XX_VPC_PERFCOUNTER0_SELECT 0xE64
+#define A3XX_VPC_PERFCOUNTER1_SELECT 0xE65
 #define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
+#define A3XX_UCHE_PERFCOUNTER0_SELECT 0xE84
+#define A3XX_UCHE_PERFCOUNTER1_SELECT 0xE85
+#define A3XX_UCHE_PERFCOUNTER2_SELECT 0xE86
+#define A3XX_UCHE_PERFCOUNTER3_SELECT 0xE87
+#define A3XX_UCHE_PERFCOUNTER4_SELECT 0xE88
+#define A3XX_UCHE_PERFCOUNTER5_SELECT 0xE89
 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER0_SELECT 0xEC4
+#define A3XX_SP_PERFCOUNTER1_SELECT 0xEC5
+#define A3XX_SP_PERFCOUNTER2_SELECT 0xEC6
+#define A3XX_SP_PERFCOUNTER3_SELECT 0xEC7
+#define A3XX_SP_PERFCOUNTER4_SELECT 0xEC8
 #define A3XX_SP_PERFCOUNTER5_SELECT 0xEC9
 #define A3XX_SP_PERFCOUNTER6_SELECT 0xECA
 #define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
+#define A3XX_TP_PERFCOUNTER0_SELECT 0xF04
+#define A3XX_TP_PERFCOUNTER1_SELECT 0xF05
+#define A3XX_TP_PERFCOUNTER2_SELECT 0xF06
+#define A3XX_TP_PERFCOUNTER3_SELECT 0xF07
+#define A3XX_TP_PERFCOUNTER4_SELECT 0xF08
+#define A3XX_TP_PERFCOUNTER5_SELECT 0xF09
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
 #define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
@@ -273,8 +398,10 @@
 #define A3XX_VBIF_OUT_AXI_AOOO 0x305F
 
 /* Bit flags for RBBM_CTL */
-#define RBBM_RBBM_CTL_RESET_PWR_CTR1  (1 << 1)
-#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1  (1 << 17)
+#define RBBM_RBBM_CTL_RESET_PWR_CTR0  BIT(0)
+#define RBBM_RBBM_CTL_RESET_PWR_CTR1  BIT(1)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR0  BIT(16)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1  BIT(17)
 
 /* Various flags used by the context switch code */
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b9f00b5..5130a09 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -215,6 +215,313 @@
 		512, 0, 2, SZ_128K, NO_VER, NO_VER },
 };
 
+/**
+ * adreno_perfcounter_init: Reserve kernel performance counters
+ * @device: device to configure
+ *
+ * The kernel needs/wants a certain group of performance counters for
+ * its own activities.  Reserve these performance counters at init time
+ * to ensure that they are always reserved for the kernel.  The performance
+ * counters used by the kernel can be obtained by the user, but these
+ * performance counters will remain active as long as the device is alive.
+ */
+
+static void adreno_perfcounter_init(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (adreno_dev->gpudev->perfcounter_init)
+		adreno_dev->gpudev->perfcounter_init(adreno_dev);
+};
+
+/**
+ * adreno_perfcounter_start: Enable performance counters
+ * @adreno_dev: Adreno device to configure
+ *
+ * Ensure all performance counters are enabled that are allocated.  Since
+ * the device was most likely stopped, we can't trust that the counters
+ * are still valid so make it so.
+ */
+
+static void adreno_perfcounter_start(struct adreno_device *adreno_dev)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int i, j;
+
+	/* group id iter */
+	for (i = 0; i < counters->group_count; i++) {
+		group = &(counters->groups[i]);
+
+		/* countable iter */
+		for (j = 0; j < group->reg_count; j++) {
+			if (group->regs[j].countable ==
+					KGSL_PERFCOUNTER_NOT_USED)
+				continue;
+
+			if (adreno_dev->gpudev->perfcounter_enable)
+				adreno_dev->gpudev->perfcounter_enable(
+					adreno_dev, i, j,
+					group->regs[j].countable);
+		}
+	}
+}
+
+/**
+ * adreno_perfcounter_read_group: Determine which countables are in counters
+ * @adreno_dev: Adreno device to configure
+ * @reads: List of kgsl_perfcounter_read_groups
+ * @count: Length of list
+ *
+ * Read the performance counters for the groupid/countable pairs and return
+ * the 64 bit result for each pair
+ */
+
+int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
+	struct kgsl_perfcounter_read_group *reads, unsigned int count)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	struct kgsl_perfcounter_read_group *list = NULL;
+	unsigned int i, j;
+	int ret = 0;
+
+	/* perfcounter get/put/query/read not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	/* sanity check for later */
+	if (!adreno_dev->gpudev->perfcounter_read)
+		return -EINVAL;
+
+	/* sanity check params passed in */
+	if (reads == NULL || count == 0 || count > 100)
+		return -EINVAL;
+
+	/* verify valid inputs group ids and countables */
+	for (i = 0; i < count; i++) {
+		if (reads[i].groupid >= counters->group_count)
+			return -EINVAL;
+	}
+
+	list = kmalloc(sizeof(struct kgsl_perfcounter_read_group) * count,
+			GFP_KERNEL);
+	if (!list)
+		return -ENOMEM;
+
+	if (copy_from_user(list, reads,
+			sizeof(struct kgsl_perfcounter_read_group) * count)) {
+		ret = -EFAULT;
+		goto done;
+	}
+
+	/* list iterator */
+	for (j = 0; j < count; j++) {
+		list[j].value = 0;
+
+		group = &(counters->groups[list[j].groupid]);
+
+		/* group/counter iterator */
+		for (i = 0; i < group->reg_count; i++) {
+			if (group->regs[i].countable == list[j].countable) {
+				list[j].value =
+					adreno_dev->gpudev->perfcounter_read(
+					adreno_dev, list[j].groupid,
+					i, group->regs[i].offset);
+				break;
+			}
+		}
+	}
+
+	/* write the data */
+	if (copy_to_user(reads, list,
+			sizeof(struct kgsl_perfcounter_read_group) *
+			count) != 0)
+		ret = -EFAULT;
+
+done:
+	kfree(list);
+	return ret;
+}
+
+/**
+ * adreno_perfcounter_query_group: Determine which countables are in counters
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countables: Return list of all countables in the groups counters
+ * @count: Max length of the array
+ * @max_counters: max counters for the groupid
+ *
+ * Query the current state of counters for the group.
+ */
+
+int adreno_perfcounter_query_group(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int *countables, unsigned int count,
+	unsigned int *max_counters)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int i;
+
+	*max_counters = 0;
+
+	/* perfcounter get/put/query not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	if (groupid >= counters->group_count)
+		return -EINVAL;
+
+	group = &(counters->groups[groupid]);
+	*max_counters = group->reg_count;
+
+	/*
+	 * if NULL countable or *count of zero, return max reg_count in
+	 * *max_counters and return success
+	 */
+	if (countables == NULL || count == 0)
+		return 0;
+
+	/*
+	 * Go through all available counters.  Write upto *count * countable
+	 * values.
+	 */
+	for (i = 0; i < group->reg_count && i < count; i++) {
+		if (copy_to_user(&countables[i], &(group->regs[i].countable),
+				sizeof(unsigned int)) != 0)
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * adreno_perfcounter_get: Try to put a countable in an available counter
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countable: Countable desired to be in a counter
+ * @offset: Return offset of the countable
+ * @flags: Used to setup kernel perf counters
+ *
+ * Try to place a countable in an available counter.  If the countable is
+ * already in a counter, reference count the counter/countable pair resource
+ * and return success
+ */
+
+int adreno_perfcounter_get(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable, unsigned int *offset,
+	unsigned int flags)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+	unsigned int i, empty = -1;
+
+	/* always clear return variables */
+	if (offset)
+		*offset = 0;
+
+	/* perfcounter get/put/query not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	if (groupid >= counters->group_count)
+		return -EINVAL;
+
+	group = &(counters->groups[groupid]);
+
+	/*
+	 * Check if the countable is already associated with a counter.
+	 * Refcount and return the offset, otherwise, try and find an empty
+	 * counter and assign the countable to it.
+	 */
+	for (i = 0; i < group->reg_count; i++) {
+		if (group->regs[i].countable == countable) {
+			/* Countable already associated with counter */
+			group->regs[i].refcount++;
+			group->regs[i].flags |= flags;
+			if (offset)
+				*offset = group->regs[i].offset;
+			return 0;
+		} else if (group->regs[i].countable ==
+			KGSL_PERFCOUNTER_NOT_USED) {
+			/* keep track of unused counter */
+			empty = i;
+		}
+	}
+
+	/* no available counters, so do nothing else */
+	if (empty == -1)
+		return -EBUSY;
+
+	/* initialize the new counter */
+	group->regs[empty].countable = countable;
+	group->regs[empty].refcount = 1;
+
+	/* enable the new counter */
+	adreno_dev->gpudev->perfcounter_enable(adreno_dev, groupid, empty,
+		countable);
+
+	group->regs[empty].flags = flags;
+
+	if (offset)
+		*offset = group->regs[empty].offset;
+
+	return 0;
+}
+
+
+/**
+ * adreno_perfcounter_put: Release a countable from counter resource
+ * @adreno_dev: Adreno device to configure
+ * @groupid: Desired performance counter group
+ * @countable: Countable desired to be freed from a  counter
+ *
+ * Put a performance counter/countable pair that was previously received.  If
+ * noone else is using the countable, free up the counter for others.
+ */
+int adreno_perfcounter_put(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable)
+{
+	struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
+	struct adreno_perfcount_group *group;
+
+	unsigned int i;
+
+	/* perfcounter get/put/query not allowed on a2xx */
+	if (adreno_is_a2xx(adreno_dev))
+		return -EINVAL;
+
+	if (groupid >= counters->group_count)
+		return -EINVAL;
+
+	group = &(counters->groups[groupid]);
+
+	for (i = 0; i < group->reg_count; i++) {
+		if (group->regs[i].countable == countable) {
+			if (group->regs[i].refcount > 0) {
+				group->regs[i].refcount--;
+
+				/*
+				 * book keeping to ensure we never free a
+				 * perf counter used by kernel
+				 */
+				if (group->regs[i].flags &&
+					group->regs[i].refcount == 0)
+					group->regs[i].refcount++;
+
+				/* make available if not used */
+				if (group->regs[i].refcount == 0)
+					group->regs[i].countable =
+						KGSL_PERFCOUNTER_NOT_USED;
+			}
+
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 {
 	irqreturn_t result;
@@ -1280,15 +1587,7 @@
 	 */
 	ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
 
-	/* Add A3XX specific registers for hang detection */
-	if (adreno_is_a3xx(adreno_dev)) {
-		ft_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
-		ft_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
-		ft_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
-		ft_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
-		ft_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
-		ft_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
-	}
+	adreno_perfcounter_init(device);
 
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
@@ -1346,6 +1645,8 @@
 	if (KGSL_STATE_DUMP_AND_FT != device->state)
 		mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
 
+	adreno_perfcounter_start(adreno_dev);
+
 	device->reset_counter++;
 
 	return 0;
@@ -3202,27 +3503,55 @@
 static long adreno_ioctl(struct kgsl_device_private *dev_priv,
 			      unsigned int cmd, void *data)
 {
+	struct kgsl_device *device = dev_priv->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int result = 0;
-	struct kgsl_drawctxt_set_bin_base_offset *binbase;
-	struct kgsl_context *context;
 
 	switch (cmd) {
-	case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET:
+	case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET: {
+		struct kgsl_drawctxt_set_bin_base_offset *binbase = data;
+		struct kgsl_context *context;
+
 		binbase = data;
 
 		context = kgsl_find_context(dev_priv, binbase->drawctxt_id);
 		if (context) {
 			adreno_drawctxt_set_bin_base_offset(
-				dev_priv->device, context, binbase->offset);
+				device, context, binbase->offset);
 		} else {
 			result = -EINVAL;
-			KGSL_DRV_ERR(dev_priv->device,
+			KGSL_DRV_ERR(device,
 				"invalid drawctxt drawctxt_id %d "
 				"device_id=%d\n",
-				binbase->drawctxt_id, dev_priv->device->id);
+				binbase->drawctxt_id, device->id);
 		}
 		break;
-
+	}
+	case IOCTL_KGSL_PERFCOUNTER_GET: {
+		struct kgsl_perfcounter_get *get = data;
+		result = adreno_perfcounter_get(adreno_dev, get->groupid,
+			get->countable, &get->offset, PERFCOUNTER_FLAG_NONE);
+		break;
+	}
+	case IOCTL_KGSL_PERFCOUNTER_PUT: {
+		struct kgsl_perfcounter_put *put = data;
+		result = adreno_perfcounter_put(adreno_dev, put->groupid,
+			put->countable);
+		break;
+	}
+	case IOCTL_KGSL_PERFCOUNTER_QUERY: {
+		struct kgsl_perfcounter_query *query = data;
+		result = adreno_perfcounter_query_group(adreno_dev,
+			query->groupid, query->countables,
+			query->count, &query->max_counters);
+		break;
+	}
+	case IOCTL_KGSL_PERFCOUNTER_READ: {
+		struct kgsl_perfcounter_read *read = data;
+		result = adreno_perfcounter_read_group(adreno_dev,
+			read->reads, read->count);
+		break;
+	}
 	default:
 		KGSL_DRV_INFO(dev_priv->device,
 			"invalid ioctl code %08x\n", cmd);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 6c57078..68133d4 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -115,6 +115,44 @@
 	unsigned int gpu_cycles;
 };
 
+#define PERFCOUNTER_FLAG_NONE 0x0
+#define PERFCOUNTER_FLAG_KERNEL 0x1
+
+/* Structs to maintain the list of active performance counters */
+
+/**
+ * struct adreno_perfcount_register: register state
+ * @countable: countable the register holds
+ * @refcount: number of users of the register
+ * @offset: register hardware offset
+ */
+struct adreno_perfcount_register {
+	unsigned int countable;
+	unsigned int refcount;
+	unsigned int offset;
+	unsigned int flags;
+};
+
+/**
+ * struct adreno_perfcount_group: registers for a hardware group
+ * @regs: available registers for this group
+ * @reg_count: total registers for this group
+ */
+struct adreno_perfcount_group {
+	struct adreno_perfcount_register *regs;
+	unsigned int reg_count;
+};
+
+/**
+ * adreno_perfcounts: all available perfcounter groups
+ * @groups: available groups for this device
+ * @group_count: total groups for this device
+ */
+struct adreno_perfcounters {
+	struct adreno_perfcount_group *groups;
+	unsigned int group_count;
+};
+
 struct adreno_gpudev {
 	/*
 	 * These registers are in a different location on A3XX,  so define
@@ -126,6 +164,8 @@
 	/* keeps track of when we need to execute the draw workaround code */
 	int ctx_switches_since_last_draw;
 
+	struct adreno_perfcounters *perfcounters;
+
 	/* GPU specific function hooks */
 	int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
 	void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
@@ -137,8 +177,14 @@
 	unsigned int (*irq_pending)(struct adreno_device *);
 	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 	int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
+	void (*perfcounter_init)(struct adreno_device *);
 	void (*start)(struct adreno_device *);
 	unsigned int (*busy_cycles)(struct adreno_device *);
+	void (*perfcounter_enable)(struct adreno_device *, unsigned int group,
+		unsigned int counter, unsigned int countable);
+	uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
+		unsigned int group, unsigned int counter,
+		unsigned int offset);
 };
 
 /*
@@ -258,6 +304,13 @@
 unsigned int adreno_ft_detect(struct kgsl_device *device,
 						unsigned int *prev_reg_val);
 
+int adreno_perfcounter_get(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable, unsigned int *offset,
+	unsigned int flags);
+
+int adreno_perfcounter_put(struct adreno_device *adreno_dev,
+	unsigned int groupid, unsigned int countable);
+
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
 	return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f1024d6..a825e90 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2603,6 +2603,213 @@
 	queue_work(device->work_queue, &device->ts_expired_ws);
 }
 
+/**
+ * struct a3xx_perfcounter_register - Define a performance counter register
+ * @load_bit: the bit to set in RBBM_LOAD_CMD0/RBBM_LOAD_CMD1 to force the RBBM
+ * to load the reset value into the appropriate counter
+ * @select: The dword offset of the register to write the selected
+ * countable into
+ */
+
+struct a3xx_perfcounter_register {
+	unsigned int load_bit;
+	unsigned int select;
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_cp[] = {
+	{ 0, A3XX_CP_PERFCOUNTER_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rbbm[] = {
+	{ 1, A3XX_RBBM_PERFCOUNTER0_SELECT },
+	{ 2, A3XX_RBBM_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_pc[] = {
+	{ 3, A3XX_PC_PERFCOUNTER0_SELECT },
+	{ 4, A3XX_PC_PERFCOUNTER1_SELECT },
+	{ 5, A3XX_PC_PERFCOUNTER2_SELECT },
+	{ 6, A3XX_PC_PERFCOUNTER3_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vfd[] = {
+	{ 7, A3XX_VFD_PERFCOUNTER0_SELECT },
+	{ 8, A3XX_VFD_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_hlsq[] = {
+	{ 9, A3XX_HLSQ_PERFCOUNTER0_SELECT },
+	{ 10, A3XX_HLSQ_PERFCOUNTER1_SELECT },
+	{ 11, A3XX_HLSQ_PERFCOUNTER2_SELECT },
+	{ 12, A3XX_HLSQ_PERFCOUNTER3_SELECT },
+	{ 13, A3XX_HLSQ_PERFCOUNTER4_SELECT },
+	{ 14, A3XX_HLSQ_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vpc[] = {
+	{ 15, A3XX_VPC_PERFCOUNTER0_SELECT },
+	{ 16, A3XX_VPC_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tse[] = {
+	{ 17, A3XX_GRAS_PERFCOUNTER0_SELECT },
+	{ 18, A3XX_GRAS_PERFCOUNTER1_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_ras[] = {
+	{ 19, A3XX_GRAS_PERFCOUNTER2_SELECT },
+	{ 20, A3XX_GRAS_PERFCOUNTER3_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_uche[] = {
+	{ 21, A3XX_UCHE_PERFCOUNTER0_SELECT },
+	{ 22, A3XX_UCHE_PERFCOUNTER1_SELECT },
+	{ 23, A3XX_UCHE_PERFCOUNTER2_SELECT },
+	{ 24, A3XX_UCHE_PERFCOUNTER3_SELECT },
+	{ 25, A3XX_UCHE_PERFCOUNTER4_SELECT },
+	{ 26, A3XX_UCHE_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tp[] = {
+	{ 27, A3XX_TP_PERFCOUNTER0_SELECT },
+	{ 28, A3XX_TP_PERFCOUNTER1_SELECT },
+	{ 29, A3XX_TP_PERFCOUNTER2_SELECT },
+	{ 30, A3XX_TP_PERFCOUNTER3_SELECT },
+	{ 31, A3XX_TP_PERFCOUNTER4_SELECT },
+	{ 32, A3XX_TP_PERFCOUNTER5_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_sp[] = {
+	{ 33, A3XX_SP_PERFCOUNTER0_SELECT },
+	{ 34, A3XX_SP_PERFCOUNTER1_SELECT },
+	{ 35, A3XX_SP_PERFCOUNTER2_SELECT },
+	{ 36, A3XX_SP_PERFCOUNTER3_SELECT },
+	{ 37, A3XX_SP_PERFCOUNTER4_SELECT },
+	{ 38, A3XX_SP_PERFCOUNTER5_SELECT },
+	{ 39, A3XX_SP_PERFCOUNTER6_SELECT },
+	{ 40, A3XX_SP_PERFCOUNTER7_SELECT },
+};
+
+static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rb[] = {
+	{ 41, A3XX_RB_PERFCOUNTER0_SELECT },
+	{ 42, A3XX_RB_PERFCOUNTER1_SELECT },
+};
+
+#define REGCOUNTER_GROUP(_x) { (_x), ARRAY_SIZE((_x)) }
+
+static struct {
+	struct a3xx_perfcounter_register *regs;
+	int count;
+} a3xx_perfcounter_reglist[] = {
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_cp),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_rbbm),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_pc),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_vfd),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_hlsq),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_vpc),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_tse),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_ras),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_uche),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_tp),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_sp),
+	REGCOUNTER_GROUP(a3xx_perfcounter_reg_rb),
+};
+
+static void a3xx_perfcounter_enable_pwr(struct kgsl_device *device,
+	unsigned int countable)
+{
+	unsigned int in, out;
+
+	adreno_regread(device, A3XX_RBBM_RBBM_CTL, &in);
+
+	if (countable == 0)
+		out = in | RBBM_RBBM_CTL_RESET_PWR_CTR0;
+	else
+		out = in | RBBM_RBBM_CTL_RESET_PWR_CTR1;
+
+	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+
+	if (countable == 0)
+		out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR0;
+	else
+		out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
+
+	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out);
+
+	return;
+}
+
+/*
+ * a3xx_perfcounter_enable - Configure a performance counter for a countable
+ * @adreno_dev -  Adreno device to configure
+ * @group - Desired performance counter group
+ * @counter - Desired performance counter in the group
+ * @countable - Desired countable
+ *
+ * Physically set up a counter within a group with the desired countable
+ */
+
+static void a3xx_perfcounter_enable(struct adreno_device *adreno_dev,
+	unsigned int group, unsigned int counter, unsigned int countable)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	unsigned int val = 0;
+	struct a3xx_perfcounter_register *reg;
+
+	if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+		return;
+
+	if (counter > a3xx_perfcounter_reglist[group].count)
+		return;
+
+	/* Special case - power */
+	if (group == KGSL_PERFCOUNTER_GROUP_PWR)
+		return a3xx_perfcounter_enable_pwr(device, countable);
+
+	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+
+	/* Select the desired perfcounter */
+	adreno_regwrite(device, reg->select, countable);
+
+	if (reg->load_bit < 32) {
+		val = 1 << reg->load_bit;
+		adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val);
+	} else {
+		val  = 1 << (reg->load_bit - 32);
+		adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val);
+	}
+}
+
+static uint64_t a3xx_perfcounter_read(struct adreno_device *adreno_dev,
+	unsigned int group, unsigned int counter,
+	unsigned int offset)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct a3xx_perfcounter_register *reg = NULL;
+	unsigned int lo = 0, hi = 0;
+	unsigned int val;
+
+	if (group > ARRAY_SIZE(a3xx_perfcounter_reglist))
+		return 0;
+
+	reg = &(a3xx_perfcounter_reglist[group].regs[counter]);
+
+	/* Freeze the counter */
+	adreno_regread(device, A3XX_RBBM_PERFCTR_CTL, &val);
+	val &= ~reg->load_bit;
+	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+
+	/* Read the values */
+	adreno_regread(device, offset, &lo);
+	adreno_regread(device, offset + 1, &hi);
+
+	/* Re-Enable the counter */
+	val |= reg->load_bit;
+	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val);
+
+	return (((uint64_t) hi) << 32) | lo;
+}
+
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
 
 #define A3XX_INT_MASK \
@@ -2835,12 +3042,45 @@
 	{ adreno_is_a305b, a305b_vbif },
 };
 
+static void a3xx_perfcounter_init(struct adreno_device *adreno_dev)
+{
+	/*
+	 * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes
+	 * all ALU instruction execution regardless precision or shader ID.
+	 * Set SP to count SP0_ICL1_MISSES, It counts
+	 * USP L1 instruction miss request.
+	 * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
+	 * counts USP flow control instruction execution.
+	 * we will use this to augment our hang detection
+	 */
+	if (adreno_dev->fast_hang_detect) {
+		adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+			SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6],
+			PERFCOUNTER_FLAG_KERNEL);
+		ft_detect_regs[7] = ft_detect_regs[6] + 1;
+		adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+			SP0_ICL1_MISSES, &ft_detect_regs[8],
+			PERFCOUNTER_FLAG_KERNEL);
+		ft_detect_regs[9] = ft_detect_regs[8] + 1;
+		adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+			SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
+			PERFCOUNTER_FLAG_KERNEL);
+		ft_detect_regs[11] = ft_detect_regs[10] + 1;
+	}
+
+	adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
+		SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL);
+
+	/* Reserve and start countable 1 in the PWR perfcounter group */
+	adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
+			NULL, PERFCOUNTER_FLAG_KERNEL);
+}
+
 static void a3xx_start(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	struct a3xx_vbif_data *vbif = NULL;
 	int i;
-	unsigned int reg;
 
 	for (i = 0; i < ARRAY_SIZE(a3xx_vbif_platforms); i++) {
 		if (a3xx_vbif_platforms[i].devfunc(adreno_dev)) {
@@ -2904,39 +3144,121 @@
 	/* Turn on performance counters */
 	adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
 
-	/*
-	 * Set SP perfcounter 5 to count SP_ALU_ACTIVE_CYCLES, it includes
-	 * all ALU instruction execution regardless precision or shader ID.
-	 * Set SP perfcounter 6 to count SP0_ICL1_MISSES, It counts
-	 * USP L1 instruction miss request.
-	 * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS, it
-	 * counts USP flow control instruction execution.
-	 * we will use this to augment our hang detection
-	 */
-	if (adreno_dev->fast_hang_detect) {
-		adreno_regwrite(device, A3XX_SP_PERFCOUNTER5_SELECT,
-			SP_ALU_ACTIVE_CYCLES);
-		adreno_regwrite(device, A3XX_SP_PERFCOUNTER6_SELECT,
-			SP0_ICL1_MISSES);
-		adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
-			SP_FS_CFLOW_INSTRUCTIONS);
-	}
-
-	adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
-		SP_FS_FULL_ALU_INSTRUCTIONS);
-
 	/* Turn on the GPU busy counter and let it run free */
 
 	adreno_dev->gpu_cycles = 0;
-
-	adreno_regread(device, A3XX_RBBM_RBBM_CTL, &reg);
-	reg |= RBBM_RBBM_CTL_RESET_PWR_CTR1;
-	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg);
-	reg &= ~RBBM_RBBM_CTL_RESET_PWR_CTR1;
-	reg |= RBBM_RBBM_CTL_ENABLE_PWR_CTR1;
-	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg);
 }
 
+/*
+ * Define the available perfcounter groups - these get used by
+ * adreno_perfcounter_get and adreno_perfcounter_put
+ */
+
+static struct adreno_perfcount_register a3xx_perfcounters_cp[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_CP_0_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pc[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_3_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tse[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_ras[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_uche[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_tp[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_5_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_sp[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_1_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_2_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_3_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_4_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_5_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_6_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_7_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_rb[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_1_LO, 0 },
+};
+
+static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = {
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_0_LO, 0 },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_1_LO, 0 },
+};
+
+static struct adreno_perfcount_group a3xx_perfcounter_groups[] = {
+	{ a3xx_perfcounters_cp, ARRAY_SIZE(a3xx_perfcounters_cp) },
+	{ a3xx_perfcounters_rbbm, ARRAY_SIZE(a3xx_perfcounters_rbbm) },
+	{ a3xx_perfcounters_pc, ARRAY_SIZE(a3xx_perfcounters_pc) },
+	{ a3xx_perfcounters_vfd, ARRAY_SIZE(a3xx_perfcounters_vfd) },
+	{ a3xx_perfcounters_hlsq, ARRAY_SIZE(a3xx_perfcounters_hlsq) },
+	{ a3xx_perfcounters_vpc, ARRAY_SIZE(a3xx_perfcounters_vpc) },
+	{ a3xx_perfcounters_tse, ARRAY_SIZE(a3xx_perfcounters_tse) },
+	{ a3xx_perfcounters_ras, ARRAY_SIZE(a3xx_perfcounters_ras) },
+	{ a3xx_perfcounters_uche, ARRAY_SIZE(a3xx_perfcounters_uche) },
+	{ a3xx_perfcounters_tp, ARRAY_SIZE(a3xx_perfcounters_tp) },
+	{ a3xx_perfcounters_sp, ARRAY_SIZE(a3xx_perfcounters_sp) },
+	{ a3xx_perfcounters_rb, ARRAY_SIZE(a3xx_perfcounters_rb) },
+	{ a3xx_perfcounters_pwr, ARRAY_SIZE(a3xx_perfcounters_pwr) },
+};
+
+static struct adreno_perfcounters a3xx_perfcounters = {
+	a3xx_perfcounter_groups,
+	ARRAY_SIZE(a3xx_perfcounter_groups),
+};
+
 /* Defined in adreno_a3xx_snapshot.c */
 void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
 	int *remain, int hang);
@@ -2945,16 +3267,20 @@
 	.reg_rbbm_status = A3XX_RBBM_STATUS,
 	.reg_cp_pfp_ucode_addr = A3XX_CP_PFP_UCODE_ADDR,
 	.reg_cp_pfp_ucode_data = A3XX_CP_PFP_UCODE_DATA,
+	.perfcounters = &a3xx_perfcounters,
 
 	.ctxt_create = a3xx_drawctxt_create,
 	.ctxt_save = a3xx_drawctxt_save,
 	.ctxt_restore = a3xx_drawctxt_restore,
 	.ctxt_draw_workaround = NULL,
 	.rb_init = a3xx_rb_init,
+	.perfcounter_init = a3xx_perfcounter_init,
 	.irq_control = a3xx_irq_control,
 	.irq_handler = a3xx_irq_handler,
 	.irq_pending = a3xx_irq_pending,
 	.busy_cycles = a3xx_busy_cycles,
 	.start = a3xx_start,
 	.snapshot = a3xx_snapshot,
+	.perfcounter_enable = a3xx_perfcounter_enable,
+	.perfcounter_read = a3xx_perfcounter_read,
 };
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 60c2da3..b52df44 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -365,7 +365,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
+EXPORT_SYMBOL(qpnp_adc_scale_pmic_therm);
 
 int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
 		struct qpnp_adc_tm_btm_param *param,
@@ -400,7 +400,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
+EXPORT_SYMBOL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
 
 /* Scales the ADC code to degC using the mapping
  * table for the XO thermistor.
@@ -426,7 +426,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
+EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
 
 int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -444,7 +444,7 @@
 			bat_voltage,
 			&adc_chan_result->physical);
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
+EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
 
 int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -462,7 +462,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu1);
+EXPORT_SYMBOL(qpnp_adc_scale_therm_pu1);
 
 int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -480,7 +480,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
+EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
 
 int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
 {
@@ -506,7 +506,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
+EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
 
 int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
 {
@@ -537,7 +537,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
+EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2);
 
 int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -553,7 +553,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
+EXPORT_SYMBOL(qpnp_adc_scale_batt_id);
 
 int32_t qpnp_adc_scale_default(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -610,7 +610,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
+EXPORT_SYMBOL(qpnp_adc_scale_default);
 
 int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
 		uint32_t *low_threshold, uint32_t *high_threshold)
@@ -631,7 +631,7 @@
 				param->low_thr);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
+EXPORT_SYMBOL(qpnp_adc_usb_scaler);
 
 int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
 		uint32_t *low_threshold, uint32_t *high_threshold)
@@ -652,7 +652,7 @@
 				param->low_thr);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_vbatt_rscaler);
+EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
 
 int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
 		uint32_t *low_threshold, uint32_t *high_threshold)
@@ -704,7 +704,7 @@
 				*low_threshold);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
+EXPORT_SYMBOL(qpnp_adc_btm_scaler);
 
 int32_t qpnp_vadc_check_result(int32_t *data)
 {
@@ -715,7 +715,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
+EXPORT_SYMBOL(qpnp_vadc_check_result);
 
 int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
 			struct qpnp_adc_drv *adc_qpnp)
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 60dcada..1fd4fee 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -409,7 +409,7 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_calibrate_for_trim(void)
+int32_t qpnp_iadc_calibrate_for_trim(void)
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	uint8_t rslt_lsb, rslt_msb;
@@ -487,6 +487,7 @@
 	mutex_unlock(&iadc->adc->adc_lock);
 	return rc;
 }
+EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
 
 static void qpnp_iadc_work(struct work_struct *work)
 {
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 0470a62..e268541 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -741,7 +741,7 @@
 	return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
 				channel, result);
 }
-EXPORT_SYMBOL_GPL(qpnp_vadc_read);
+EXPORT_SYMBOL(qpnp_vadc_read);
 
 static void qpnp_vadc_lock(void)
 {
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 202edc0..ac06fc5 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -61,6 +61,7 @@
 #define WLED_MAX_CURR_MASK		0x19
 #define WLED_OP_FDBCK_MASK		0x07
 #define WLED_OP_FDBCK_BIT_SHFT		0x00
+#define WLED_OP_FDBCK_DEFAULT		0x00
 
 #define WLED_MAX_LEVEL			4095
 #define WLED_8_BIT_MASK			0xFF
@@ -90,6 +91,8 @@
 #define FLASH_VREG_OK_FORCE(base)	(base + 0x4F)
 #define FLASH_ENABLE_CONTROL(base)	(base + 0x46)
 #define FLASH_LED_STROBE_CTRL(base)	(base + 0x47)
+#define FLASH_LED_UNLOCK_SECURE(base)	(base + 0xD0)
+#define FLASH_LED_TORCH(base)		(base + 0xE4)
 
 #define FLASH_MAX_LEVEL			0x4F
 #define	FLASH_NO_MASK			0x00
@@ -99,6 +102,7 @@
 #define FLASH_HEADROOM_MASK		0x03
 #define FLASH_SAFETY_TIMER_MASK		0x7F
 #define FLASH_CURRENT_MASK		0xFF
+#define FLASH_MAX_CURRENT_MASK		0x7F
 #define FLASH_TMR_MASK			0x03
 #define FLASH_TMR_WATCHDOG		0x03
 #define FLASH_TMR_SAFETY		0x00
@@ -117,17 +121,26 @@
 #define FLASH_ENABLE_LED_1		0x20
 #define FLASH_INIT_MASK			0xE0
 
-#define FLASH_STROBE_ALL		0xC0
-#define FLASH_STROBE_MASK		0xC0
+#define FLASH_STROBE_SW			0xC0
+#define FLASH_STROBE_HW			0xC4
+#define FLASH_STROBE_MASK		0xC7
 #define FLASH_LED_0_OUTPUT		0x80
 #define FLASH_LED_1_OUTPUT		0x40
 
 #define FLASH_CURRENT_PRGM_MIN		1
 #define FLASH_CURRENT_PRGM_SHIFT	1
+#define FLASH_CURRENT_MAX		0x4F
+#define FLASH_CURRENT_TORCH		0x0F
 
 #define FLASH_DURATION_200ms		0x13
 #define FLASH_CLAMP_200mA		0x0F
 
+#define FLASH_TORCH_MASK		0x03
+#define FLASH_LED_TORCH_ENABLE		0x00
+#define FLASH_LED_TORCH_DISABLE		0x03
+#define FLASH_UNLOCK_SECURE		0xA5
+#define FLASH_SECURE_MASK		0xFF
+
 #define LED_TRIGGER_DEFAULT		"none"
 
 #define RGB_LED_SRC_SEL(base)		(base + 0x45)
@@ -245,9 +258,9 @@
 	u8	cp_select;
 	u8	ctrl_delay_us;
 	u8	switch_freq;
+	u8	op_fdbck;
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
-	bool	op_fdbck;
 };
 
 /**
@@ -259,9 +272,11 @@
  *  @enable_module - enable address for particular flash
  *  @trigger_flash - trigger flash
  *  @startup_dly - startup delay for flash
+ *  @strobe_type - select between sw and hw strobe
  *  @current_addr - address to write for current
  *  @second_addr - address of secondary flash to be written
  *  @safety_timer - enable safety timer or watchdog timer
+ *  @torch_enable - enable flash LED torch mode
  */
 struct flash_config_data {
 	u8	current_prgm;
@@ -271,9 +286,11 @@
 	u8	enable_module;
 	u8	trigger_flash;
 	u8	startup_dly;
+	u8	strobe_type;
 	u16	current_addr;
 	u16	second_addr;
 	bool	safety_timer;
+	bool	torch_enable;
 };
 
 /**
@@ -456,62 +473,176 @@
 
 	/* Set led current */
 	if (val > 0) {
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
+		if (led->flash_cfg->torch_enable) {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_UNLOCK_SECURE(led->base),
+				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Secure reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_TORCH(led->base),
+				FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Torch reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Max current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->current_addr,
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Current reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->second_addr,
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"2nd Current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				return rc;
+			}
+		} else {
+			rc = qpnp_led_masked_write(led,
+				FLASH_MAX_CURR(led->base),
+				FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Max current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			/* Write 0x80 to MODULE_ENABLE before writing 0xE0
+			 * in order to avoid reg value goes from 0x00 to
+			 * 0xE0. This causes a hardware bug.
+			 */
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->current_addr,
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->current_prgm);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Current reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				led->flash_cfg->second_addr,
+				FLASH_CURRENT_MASK,
+				led->flash_cfg->current_prgm);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"2nd Current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_CLAMP_CURR(led->base),
+				FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Clamp Current reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				return rc;
+			}
 		}
 
-		rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
-			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Current reg write failed(%d)\n", rc);
-			return rc;
-		}
-
-		rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
-			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Current reg write failed(%d)\n", rc);
-			return rc;
-		}
-
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_ENABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
-		}
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			FLASH_STROBE_MASK, FLASH_STROBE_ALL);
-
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"LED %d flash write failed(%d)\n", led->id, rc);
-			return rc;
-		}
-		rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
-			FLASH_VREG_MASK, FLASH_HW_VREG_OK);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Vreg OK reg write failed(%d)\n", rc);
-			return rc;
+		if (!led->flash_cfg->strobe_type) {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				FLASH_STROBE_MASK, FLASH_STROBE_SW);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"LED %d strobe reg write failed(%d)\n",
+					led->id, rc);
+				return rc;
+			}
+		} else {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				FLASH_STROBE_MASK, FLASH_STROBE_HW);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"LED %d strobe reg write failed(%d)\n",
+					led->id, rc);
+				return rc;
+			}
 		}
 	} else {
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
+		if (led->flash_cfg->torch_enable) {
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_UNLOCK_SECURE(led->base),
+				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Secure reg write failed(%d)\n", rc);
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_TORCH(led->base),
+				FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Torch reg write failed(%d)\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_SAFETY_TIMER(led->base),
+				FLASH_SAFETY_TIMER_MASK,
+				led->flash_cfg->duration);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Safety timer reg write failed(%d)\n",
+					rc);
+				return rc;
+			}
 		}
 
 		rc = qpnp_led_masked_write(led,
@@ -523,6 +654,15 @@
 				"LED %d flash write failed(%d)\n", led->id, rc);
 			return rc;
 		}
+
+		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+			FLASH_ENABLE_MASK,
+			FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+			return rc;
+		}
 	}
 
 	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
@@ -797,6 +937,66 @@
 	return 0;
 }
 
+static ssize_t led_mode_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	unsigned long state;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL;
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret)
+		return ret;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	/* '1' to enable torch mode; '0' to switch to flash mode */
+	if (state == 1)
+		led->flash_cfg->torch_enable = true;
+	else
+		led->flash_cfg->torch_enable = false;
+
+	return count;
+}
+
+static ssize_t led_strobe_type_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct qpnp_led_data *led;
+	unsigned long state;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL;
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret)
+		return ret;
+
+	led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+	/* '0' for sw strobe; '1' for hw strobe */
+	if (state == 1)
+		led->flash_cfg->strobe_type = 1;
+	else
+		led->flash_cfg->strobe_type = 0;
+
+	return count;
+}
+
+static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
+static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
+
+static struct attribute *led_attrs[] = {
+	&dev_attr_led_mode.attr,
+	&dev_attr_strobe.attr,
+};
+
+static const struct attribute_group led_attr_group = {
+	.attrs = led_attrs,
+};
+
 static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
 {
 	int rc;
@@ -890,7 +1090,7 @@
 		return rc;
 	}
 
-	/* Set led current and enable module */
+	/* Set led current and disable module */
 	rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
 		FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
 	if (rc) {
@@ -906,6 +1106,10 @@
 			"Enable reg write failed(%d)\n", rc);
 		return rc;
 	}
+
+	led->flash_cfg->torch_enable = false;
+	led->flash_cfg->strobe_type = 0;
+
 	/* dump flash registers */
 	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
 
@@ -1099,6 +1303,13 @@
 	else if (rc != -EINVAL)
 		return rc;
 
+	led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
+	rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
+	if (!rc)
+		led->wled_cfg->op_fdbck = (u8) val;
+	else if (rc != -EINVAL)
+		return rc;
+
 	led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
 	rc = of_property_read_u32(node, "qcom,switch-freq", &val);
 	if (!rc)
@@ -1112,9 +1323,6 @@
 	led->wled_cfg->cs_out_en =
 		of_property_read_bool(node, "qcom,cs-out-en");
 
-	led->wled_cfg->op_fdbck =
-		of_property_read_bool(node, "qcom,op-fdbck");
-
 	return 0;
 }
 
@@ -1451,6 +1659,16 @@
 						 led->id, rc);
 			goto fail_id_check;
 		}
+
+		if (led->id == QPNP_ID_FLASH1_LED0 ||
+			led->id == QPNP_ID_FLASH1_LED1) {
+			rc = sysfs_create_group(&led->cdev.dev->kobj,
+							&led_attr_group);
+			if (rc)
+				goto fail_id_check;
+
+		}
+
 		/* configure default state */
 		if (led->default_on) {
 			led->cdev.brightness = led->cdev.max_brightness;
@@ -1477,8 +1695,26 @@
 	struct qpnp_led_data *led_array  = dev_get_drvdata(&spmi->dev);
 	int i, parsed_leds = led_array->num_leds;
 
-	for (i = 0; i < parsed_leds; i++)
+	for (i = 0; i < parsed_leds; i++) {
 		led_classdev_unregister(&led_array[i].cdev);
+		switch (led_array[i].id) {
+		case QPNP_ID_WLED:
+			break;
+		case QPNP_ID_FLASH1_LED0:
+		case QPNP_ID_FLASH1_LED1:
+			sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+							&led_attr_group);
+			break;
+		case QPNP_ID_RGB_RED:
+		case QPNP_ID_RGB_GREEN:
+		case QPNP_ID_RGB_BLUE:
+		default:
+			dev_err(&led_array[i].spmi_dev->dev,
+					"Invalid LED(%d)\n",
+					led_array[i].id);
+			return -EINVAL;
+		}
+	}
 
 	return 0;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index d782227..50adb13 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -1245,6 +1245,15 @@
 			"Failed to load buffer usage table: %d\n", rc);
 		goto err_load_buffer_usage_table;
 	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+			&res->max_load);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to determine max load supported: %d\n", rc);
+		goto err_load_buffer_usage_table;
+	}
+
 	return rc;
 
 err_load_buffer_usage_table:
@@ -1295,6 +1304,8 @@
 		res->load_freq_tbl[c].load = pdata->load_table[c][0];
 		res->load_freq_tbl[c].freq = pdata->load_table[c][1];
 	}
+
+	res->max_load = pdata->max_load;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 30530d4..8eecb98 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -22,7 +22,7 @@
 #include "msm_smem.h"
 #include "msm_vidc_debug.h"
 
-#define HW_RESPONSE_TIMEOUT msecs_to_jiffies(200)
+#define HW_RESPONSE_TIMEOUT 200
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -49,11 +49,6 @@
 
 #define TIME_DIFF_THRESHOLD 200
 
-/*Load is in Macroblocks (MBs) per sec. This value is calculated
- * based on one 4k video instance @ 24 fps plus one 1080p video
- * instance @ 30fps. 1 MB = 16 X 16 pixels*/
-#define MAX_LOAD 1074240
-
 static int msm_comm_get_load(struct msm_vidc_core *core,
 	enum session_type type)
 {
@@ -1265,13 +1260,32 @@
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
+
 	num_mbs_per_sec = msm_comm_get_load(inst->core, MSM_VIDC_DECODER);
 	num_mbs_per_sec += msm_comm_get_load(inst->core, MSM_VIDC_ENCODER);
-	if (num_mbs_per_sec > MAX_LOAD) {
-		dprintk(VIDC_ERR, "HW is overloaded, needed:%d max: %d\n",
-			num_mbs_per_sec, MAX_LOAD);
+	if (num_mbs_per_sec > inst->core->resources.max_load) {
+		struct msm_vidc_inst *temp;
+
+		dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
+			num_mbs_per_sec, inst->core->resources.max_load);
+		dprintk(VIDC_ERR, "Running instances:\n");
+		dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s\n", "type", "w", "h", "fps");
+		list_for_each_entry(temp, &inst->core->instances, list) {
+			mutex_lock(&temp->lock);
+			if (temp->state >= MSM_VIDC_OPEN_DONE &&
+					temp->state < MSM_VIDC_STOP_DONE) {
+				dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d\n",
+						temp->session_type,
+						temp->prop.width,
+						temp->prop.height,
+						temp->prop.fps);
+			}
+			mutex_unlock(&temp->lock);
+		}
+
 		return -ENOMEM;
 	}
+
 	hdev = inst->core->device;
 
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 1bfbaa6..e5696be 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -37,7 +37,7 @@
 #define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
 #define MAX_DEBUGFS_NAME 50
 #define DEFAULT_TIMEOUT 3
-#define DEFAULT_HEIGHT 1080
+#define DEFAULT_HEIGHT 1088
 #define DEFAULT_WIDTH 1920
 #define MIN_SUPPORTED_WIDTH 32
 #define MIN_SUPPORTED_HEIGHT 32
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 86b824b..693c1a5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -74,6 +74,7 @@
 	struct iommu_set iommu_group_set;
 	struct buffer_usage_set buffer_usage_set;
 	bool has_ocmem;
+	uint32_t max_load;
 	struct platform_device *pdev;
 };
 
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index bf6c7db..123b654 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -479,7 +479,7 @@
 
 	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
 
-	rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_ARCH_OX_OFFSET);
+	rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to create sys init pkt");
 		goto err_core_init;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index b5dd15d..8031c74 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -386,11 +386,22 @@
 	msm_smem_free(clnt, mem);
 }
 
-static void venus_hfi_write_register(u8 *base_addr, u32 reg,
+static void venus_hfi_write_register(struct venus_hfi_device *device, u32 reg,
 				u32 value, u8 *vaddr)
 {
 	u32 hwiosymaddr = reg;
+	u8 *base_addr;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return;
+	}
 
+	base_addr = device->hal_data->register_base_addr;
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Write register failed : Clocks are OFF\n");
+		return;
+	}
 	reg &= REG_ADDR_OFFSET_BITMASK;
 	if (reg == (u32)VIDC_CPU_CS_SCIACMDARG2) {
 		/* workaround to offset of FW bias */
@@ -416,14 +427,26 @@
 	wmb();
 }
 
-static int venus_hfi_read_register(u8 *base_addr, u32 reg)
+static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg)
 {
-	int rc = readl_relaxed((u32)base_addr + reg);
+	int rc ;
+	u8 *base_addr;
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+		return -EINVAL;
+	}
+
+	base_addr = device->hal_data->register_base_addr;
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Read register failed : Clocks are OFF\n");
+		return -EINVAL;
+	}
+	rc = readl_relaxed((u32)base_addr + reg);
 	rmb();
 	return rc;
 }
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device,
-	enum vidc_clocks clk_level)
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
 {
 	int i;
 	struct venus_core_clock *cl;
@@ -431,19 +454,18 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	if (device->clocks_enabled == 0) {
-		dprintk(VIDC_DBG, "VCODEC clocks are already disabled");
+	if (!device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks are already disabled");
 		goto already_disabled;
 	}
-	for (i = 0; i < clk_level; i++) {
+	for (i = 0; i <= device->clk_gating_level; i++) {
 		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
+		clk_disable(cl->clk);
 	}
 already_disabled:
 	device->clocks_enabled = 0;
 }
-static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device,
-	enum vidc_clocks clk_level)
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
 {
 	int i;
 	struct venus_core_clock *cl;
@@ -452,13 +474,13 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	if (device->clocks_enabled == 1) {
-		dprintk(VIDC_DBG, "VCODEC clocks are already enabled");
+	if (device->clocks_enabled) {
+		dprintk(VIDC_DBG, "Clocks are already enabled");
 		goto already_enabled;
 	}
-	for (i = 0; i < clk_level; i++) {
+	for (i = 0; i <= device->clk_gating_level; i++) {
 		cl = &device->resources.clock[i];
-		rc = clk_prepare_enable(cl->clk);
+		rc = clk_enable(cl->clk);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to enable clocks\n");
 			goto fail_clk_enable;
@@ -472,7 +494,7 @@
 fail_clk_enable:
 	for (; i >= 0; i--) {
 		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
+		clk_disable(cl->clk);
 	}
 	return rc;
 }
@@ -482,7 +504,7 @@
 {
 	int num_rows = clock->count;
 	struct load_freq_table *table = clock->load_freq_tbl;
-	unsigned long ret = table[num_rows-1].freq;
+	unsigned long ret = table[0].freq;
 	int i;
 	for (i = 0; i < num_rows; i++) {
 		if (num_mbs_per_sec > table[i].load)
@@ -497,11 +519,11 @@
 {
 	int rc = 0;
 	struct venus_hfi_device *device = dev;
-	device->load = load;
 	if (!device) {
 		dprintk(VIDC_ERR, "Invalid args: %p\n", device);
 		return -EINVAL;
 	}
+	device->load = load;
 	rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
 		venus_hfi_get_clock_rate(&device->resources.clock[VCODEC_CLK],
 			load));
@@ -527,20 +549,22 @@
 		dprintk(VIDC_ERR, "cannot write to shared Q's");
 		goto err_q_write;
 	}
-	result = venus_hfi_clk_gating_off(device, VCODEC_CLK);
+	mutex_lock(&device->clock_lock);
+	result = venus_hfi_clk_gating_off(device);
 	if (result) {
-		dprintk(VIDC_ERR, "VCODEC clock enable failed\n");
+		dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+			__func__);
 		goto err_q_write;
 	}
 	result = venus_hfi_scale_clocks(device, device->load);
 	if (result) {
-		dprintk(VIDC_ERR, "VCODEC clock scaling failed\n");
+		dprintk(VIDC_ERR, "Clock scaling failed\n");
 		goto err_q_write;
 	}
 	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
 		if (rx_req_is_set)
 			venus_hfi_write_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		result = 0;
@@ -549,6 +573,7 @@
 	}
 err_q_write:
 	mutex_unlock(&device->write_lock);
+	mutex_unlock(&device->clock_lock);
 	return result;
 }
 
@@ -570,11 +595,17 @@
 		goto read_error;
 	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
-
+	mutex_lock(&device->clock_lock);
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s : Clock enable failed\n", __func__);
+		goto read_error;
+	}
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
 		if (tx_req_is_set)
 			venus_hfi_write_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
@@ -584,6 +615,7 @@
 	}
 read_error:
 	mutex_unlock(&device->read_lock);
+	mutex_unlock(&device->clock_lock);
 	return rc;
 }
 
@@ -604,11 +636,18 @@
 		rc = -ENODATA;
 		goto dbg_error;
 	}
+	mutex_lock(&device->clock_lock);
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s : Clock enable failed\n", __func__);
+		goto dbg_error;
+	}
 	q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
 	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
 		if (tx_req_is_set)
 			venus_hfi_write_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_IC_SOFTINT,
 				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
 		rc = 0;
@@ -618,6 +657,7 @@
 	}
 dbg_error:
 	mutex_unlock(&device->read_lock);
+	mutex_unlock(&device->clock_lock);
 	return rc;
 }
 
@@ -822,16 +862,16 @@
 		iface_q->q_array.align_device_addr;
 	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
 
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 			VIDC_UC_REGION_ADDR,
 			(u32) dev->iface_q_table.align_device_addr, 0);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 			VIDC_UC_REGION_SIZE, SHARED_QSIZE, 0);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 		VIDC_CPU_CS_SCIACMDARG2,
 		(u32) dev->iface_q_table.align_device_addr,
 		dev->iface_q_table.align_virtual_addr);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 		VIDC_CPU_CS_SCIACMDARG1, 0x01,
 		dev->iface_q_table.align_virtual_addr);
 
@@ -851,14 +891,14 @@
 		dev->qdss.mem_data = NULL;
 	}
 	if (!IS_ERR_OR_NULL(dev->qdss.align_device_addr))
-		venus_hfi_write_register(dev->hal_data->register_base_addr,
+		venus_hfi_write_register(dev,
 			VIDC_MMAP_ADDR,
 			(u32) dev->qdss.align_device_addr, 0);
 
 	vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
 	vsfr->bufSize = SFR_SIZE;
 	if (!IS_ERR_OR_NULL(dev->sfr.align_device_addr))
-		venus_hfi_write_register(dev->hal_data->register_base_addr,
+		venus_hfi_write_register(dev,
 			VIDC_SFR_ADDR, (u32)dev->sfr.align_device_addr , 0);
 	return 0;
 fail_alloc_queue:
@@ -869,14 +909,14 @@
 {
 	u32 ctrl_status = 0, count = 0, rc = 0;
 	int max_tries = 100;
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_MASK, 0x8, 0);
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_CPU_CS_SCIACMDARG3, 1, 0);
 
 	while (!ctrl_status && count < max_tries) {
 		ctrl_status = venus_hfi_read_register(
-				device->hal_data->register_base_addr,
+				device,
 				VIDC_CPU_CS_SCIACMDARG0);
 		if ((ctrl_status & 0xFE) == 0x4) {
 			dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
@@ -903,7 +943,7 @@
 
 	reg_set = &device->res->reg_set;
 	for (i = 0; i < reg_set->count; i++) {
-		venus_hfi_write_register(device->hal_data->register_base_addr,
+		venus_hfi_write_register(device,
 				reg_set->reg_tbl[i].reg,
 				reg_set->reg_tbl[i].value, 0);
 	}
@@ -981,7 +1021,7 @@
 		goto err_core_init;
 	}
 	enable_irq(dev->hal_data->irq);
-	venus_hfi_write_register(dev->hal_data->register_base_addr,
+	venus_hfi_write_register(dev,
 		VIDC_CTRL_INIT, 0x1, 0);
 	rc = venus_hfi_core_start_cpu(dev);
 	if (rc) {
@@ -990,7 +1030,7 @@
 		goto err_core_init;
 	}
 
-	rc = create_pkt_cmd_sys_init(&pkt, HFI_ARCH_OX_OFFSET);
+	rc = create_pkt_cmd_sys_init(&pkt, HFI_VIDEO_ARCH_OX);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to create sys init pkt");
 		goto err_core_init;
@@ -1008,6 +1048,7 @@
 static int venus_hfi_core_release(void *device)
 {
 	struct venus_hfi_device *dev;
+	int rc = 0;
 	if (device) {
 		dev = device;
 	} else {
@@ -1015,13 +1056,22 @@
 		return -ENODEV;
 	}
 	if (dev->hal_client) {
-		venus_hfi_write_register(dev->hal_data->register_base_addr,
+		mutex_lock(&dev->clock_lock);
+		rc = venus_hfi_clk_gating_off(device);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s : Clock enable failed\n", __func__);
+			mutex_unlock(&dev->clock_lock);
+			return -EIO;
+		}
+		venus_hfi_write_register(dev,
 				VIDC_CPU_CS_SCIACMDARG3, 0, 0);
 		if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
 			disable_irq_nosync(dev->hal_data->irq);
 		dev->intr_status = 0;
 		venus_hfi_interface_queues_release(dev);
 	}
+	mutex_unlock(&dev->clock_lock);
 	dprintk(VIDC_INFO, "HAL exited\n");
 	return 0;
 }
@@ -1055,16 +1105,26 @@
 static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
 {
 	u32 intr_status = 0;
+	int rc = 0;
 
 	if (!device->callback)
 		return;
-
+	mutex_lock(&device->clock_lock);
+	rc = venus_hfi_clk_gating_off(device);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s : Clock enable failed\n", __func__);
+		mutex_unlock(&device->clock_lock);
+		return;
+	}
 	intr_status = venus_hfi_read_register(
-			device->hal_data->register_base_addr,
+			device,
 			VIDC_WRAPPER_INTR_STATUS);
 
 	if ((intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK) ||
-		(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) {
+		(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK) ||
+		(intr_status &
+			VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)) {
 		device->intr_status |= intr_status;
 		dprintk(VIDC_DBG, "INTERRUPT for device: 0x%x: "
 			"times: %d interrupt_status: %d",
@@ -1074,10 +1134,11 @@
 			"times: %d interrupt_status: %d",
 			(u32) device, ++device->spur_count, intr_status);
 	}
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
-	venus_hfi_write_register(device->hal_data->register_base_addr,
+	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
+	mutex_unlock(&device->clock_lock);
 	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
 }
 
@@ -1798,14 +1859,16 @@
 		return -ENODEV;
 	}
 	mutex_lock(&device->write_lock);
+	mutex_lock(&device->clock_lock);
 	rc = venus_hfi_is_cmd_pending(device);
 	ctrl_status = venus_hfi_read_register(
-		device->hal_data->register_base_addr,
+		device,
 		VIDC_CPU_CS_SCIACMDARG0);
 	if (((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
 		!= 0) && !rc)
-		venus_hfi_clk_gating_on(device, VCODEC_CLK);
+		venus_hfi_clk_gating_on(device);
 	mutex_unlock(&device->write_lock);
+	mutex_unlock(&device->clock_lock);
 	return rc;
 }
 
@@ -1826,15 +1889,14 @@
 			rc = hfi_process_msg_packet(device->callback,
 				device->device_id,
 				(struct vidc_hal_msg_pkt_hdr *) packet);
-			if (rc == HFI_MSG_SYS_IDLE)
-				rc = venus_hfi_try_clk_gating(device);
-
 		}
 		while (!venus_hfi_iface_dbgq_read(device, packet)) {
 			struct hfi_msg_sys_debug_packet *pkt =
 				(struct hfi_msg_sys_debug_packet *) packet;
 			dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
 		}
+		if (rc == HFI_MSG_SYS_IDLE)
+			rc = venus_hfi_try_clk_gating(device);
 	} else {
 		dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
 	}
@@ -2015,12 +2077,23 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-
+	if (device->clocks_enabled) {
+		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+			cl = &device->resources.clock[i];
+			clk_disable(cl->clk);
+		}
+	} else {
+		for (i = device->clk_gating_level + 1;
+			i < VCODEC_MAX_CLKS; i++) {
+			cl = &device->resources.clock[i];
+			clk_disable(cl->clk);
+		}
+	}
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
 		cl = &device->resources.clock[i];
-		clk_disable_unprepare(cl->clk);
+		clk_unprepare(cl->clk);
 	}
 	device->clocks_enabled = 0;
 }
@@ -2311,6 +2384,7 @@
 	struct vidc_resource_hdr rhdr;
 	struct venus_hfi_device *device = dev;
 	int rc = 0;
+
 	if (!device) {
 		dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
 			__func__, device);
@@ -2323,7 +2397,6 @@
 		rc = -EINVAL;
 		goto ocmem_unset_failed;
 	}
-
 	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
 	rhdr.resource_handle = (u32) &device->resources.ocmem;
 	rc = venus_hfi_core_release_resource(device, &rhdr);
@@ -2625,7 +2698,8 @@
 			__func__, device);
 		return -EINVAL;
 	}
-
+	mutex_init(&device->clock_lock);
+	device->clk_gating_level = VCODEC_CLK;
 	rc = venus_hfi_iommu_attach(device);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to attach iommu");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 7a96ff4..197c754 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -176,8 +176,10 @@
 	u32 device_id;
 	u32 load;
 	u32 clocks_enabled;
+	enum vidc_clocks clk_gating_level;
 	struct mutex read_lock;
 	struct mutex write_lock;
+	struct mutex clock_lock;
 	msm_vidc_callback callback;
 	struct vidc_mem_addr iface_q_table;
 	struct vidc_mem_addr qdss;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 72b02bb..cd54449 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -1036,7 +1036,7 @@
 {
 	int rc = 0;
 	struct wfd_device *wfd_dev = video_drvdata(filp);
-	struct wfd_inst *inst = filp->private_data;
+	struct wfd_inst *inst = file_to_inst(filp);
 
 	switch (a->id) {
 	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index fce1547..09d942a 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -182,6 +182,41 @@
 	return rc;
 }
 
+/**
+ * pm8xxx_read_register - Read a PMIC register
+ * @addr: PMIC register address
+ * @value: Output parameter which gets the value of the register read.
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_read_register(u16 addr, u8 *value)
+{
+	struct pm8xxx_misc_chip *chip;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
+
+	/* Loop over all attached PMICs and call specific functions for them. */
+	list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
+		switch (chip->version) {
+		case PM8XXX_VERSION_8921:
+			rc = pm8xxx_readb(chip->dev->parent, addr, value);
+			if (rc) {
+				pr_err("pm8xxx_readb(0x%03X) failed, rc=%d\n",
+								addr, rc);
+				break;
+			}
+		default:
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_read_register);
+
 /*
  * Set an SMPS regulator to be disabled in its CTRL register, but enabled
  * in the master enable register.  Also set it's pull down enable bit.
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 0f81285..47108c6 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -17,6 +17,7 @@
 #include <linux/io.h>		/* ioread32() */
 #include <linux/bitops.h>	/* find_first_bit() */
 #include <linux/errno.h>	/* ENODEV */
+#include <linux/memory.h>
 
 #include "bam.h"
 #include "sps_bam.h"
@@ -849,7 +850,7 @@
 
 	print_bam_test_bus_reg(base, 0);
 
-	print_bam_reg(base);
+	print_bam_selected_reg(base, BAM_MAX_EES);
 
 	num_pipes = bam_read_reg_field(base, NUM_PIPES,
 					BAM_NUM_PIPES);
@@ -857,8 +858,7 @@
 			(u32) base, num_pipes);
 
 	for (i = 0; i < num_pipes; i++)
-		print_bam_pipe_reg(base, i);
-
+		print_bam_pipe_selected_reg(base, i);
 }
 
 /**
@@ -1174,7 +1174,7 @@
 	pipes = bam[0xfbc / 4];
 #endif
 
-	SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+	SPS_INFO("\nsps:<bam-begin> --- Content of BAM-level registers---\n");
 
 	SPS_INFO("BAM_CTRL: 0x%x.\n", ctrl);
 	SPS_INFO("BAM_REVISION: 0x%x.\n", ver);
@@ -1198,7 +1198,7 @@
 			bam[i / 4], bam[(i / 4) + 1],
 			bam[(i / 4) + 2], bam[(i / 4) + 3]);
 
-	SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+	SPS_INFO("\nsps:<bam-begin> --- Content of BAM-level registers ---\n");
 }
 
 /* output the content of BAM pipe registers */
@@ -1211,7 +1211,7 @@
 	if (bam == NULL)
 		return;
 
-	SPS_INFO("\nsps:----- Content of Pipe %d registers <begin> -----\n",
+	SPS_INFO("\nsps:<pipe-begin> --- Content of Pipe %d registers ---\n",
 			pipe);
 
 	SPS_INFO("-- Pipe Management Registers --\n");
@@ -1240,47 +1240,110 @@
 			bam[i / 4], bam[(i / 4) + 1],
 			bam[(i / 4) + 2], bam[(i / 4) + 3]);
 
-	SPS_INFO("\nsps:----- Content of Pipe %d registers <end> -----\n",
+	SPS_INFO("\nsps:<pipe-end> --- Content of Pipe %d registers ---\n",
 			pipe);
 }
 
 /* output the content of selected BAM-level registers */
-void print_bam_selected_reg(void *virt_addr)
+void print_bam_selected_reg(void *virt_addr, u32 ee)
 {
 	void *base = virt_addr;
 
+	u32 bam_ctrl;
+	u32 bam_revision;
+	u32 bam_rev_num;
+	u32 bam_rev_ee_num;
+
+	u32 bam_num_pipes;
+	u32 bam_pipe_num;
+
+	u32 bam_desc_cnt_trshld;
+	u32 bam_desc_cnt_trd_val;
+
+	u32 bam_irq_en;
+	u32 bam_irq_stts;
+
+	u32 bam_irq_src_ee = 0;
+	u32 bam_irq_msk_ee = 0;
+	u32 bam_irq_unmsk_ee = 0;
+
+	u32 bam_ahb_err_ctrl;
+	u32 bam_ahb_err_addr;
+	u32 bam_ahb_err_data;
+	u32 bam_cnfg_bits;
+
+	u32 bam_sw_rev = 0;
+	u32 bam_timer = 0;
+	u32 bam_timer_ctrl = 0;
+
 	if (base == NULL)
 		return;
 
-	SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+	bam_ctrl = bam_read_reg(base, CTRL);
+	bam_revision = bam_read_reg(base, REVISION);
+	bam_rev_num = bam_read_reg_field(base, REVISION, BAM_REVISION);
+	bam_rev_ee_num = bam_read_reg_field(base, REVISION, BAM_NUM_EES);
 
-	SPS_INFO("BAM_CTRL: 0x%x\n"
-		"BAM_REVISION: 0x%x\n"
-		"BAM_NUM_EES: %d\n"
-#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
-		"BAM_CMD_DESC_EN: 0x%x\n"
-#endif
-		"BAM_NUM_PIPES: %d\n"
-		"BAM_DESC_CNT_TRSHLD: 0x%x (%d)\n"
-		"BAM_IRQ_SRCS: 0x%x\n"
-		"BAM_IRQ_SRCS_MSK: 0x%x\n"
-		"BAM_EE: %d\n"
-		"BAM_CNFG_BITS: 0x%x\n",
-		bam_read_reg(base, CTRL),
-		bam_read_reg_field(base, REVISION, BAM_REVISION),
-		bam_read_reg_field(base, REVISION, BAM_NUM_EES),
-#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
-		bam_read_reg_field(base, REVISION, BAM_CMD_DESC_EN),
-#endif
-		bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES),
-		bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
-		bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
-		bam_read_reg(base, IRQ_SRCS),
-		bam_read_reg(base, IRQ_SRCS_MSK),
-		bam_read_reg_field(base, TRUST_REG, BAM_EE),
-		bam_read_reg(base, CNFG_BITS));
+	bam_num_pipes = bam_read_reg(base, NUM_PIPES);
+	bam_pipe_num = bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES);
 
-	SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+	bam_desc_cnt_trshld = bam_read_reg(base, DESC_CNT_TRSHLD);
+	bam_desc_cnt_trd_val = bam_read_reg_field(base, DESC_CNT_TRSHLD,
+					BAM_DESC_CNT_TRSHLD);
+
+	bam_irq_en = bam_read_reg(base, IRQ_EN);
+	bam_irq_stts = bam_read_reg(base, IRQ_STTS);
+
+	if (ee < BAM_MAX_EES) {
+		bam_irq_src_ee = bam_read_reg(base, IRQ_SRCS_EE(ee));
+		bam_irq_msk_ee = bam_read_reg(base, IRQ_SRCS_MSK_EE(ee));
+		bam_irq_unmsk_ee = bam_read_reg(base, IRQ_SRCS_UNMASKED_EE(ee));
+	}
+
+	bam_ahb_err_ctrl = bam_read_reg(base, AHB_MASTER_ERR_CTRLS);
+	bam_ahb_err_addr = bam_read_reg(base, AHB_MASTER_ERR_ADDR);
+	bam_ahb_err_data = bam_read_reg(base, AHB_MASTER_ERR_DATA);
+	bam_cnfg_bits = bam_read_reg(base, CNFG_BITS);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	bam_sw_rev = bam_read_reg(base, SW_REVISION);
+	bam_timer = bam_read_reg(base, TIMER);
+	bam_timer_ctrl = bam_read_reg(base, TIMER_CTRL);
+#endif
+
+
+	SPS_INFO("\nsps:<bam-begin> --- BAM-level registers ---\n\n");
+
+	SPS_INFO("BAM_CTRL: 0x%x\n", bam_ctrl);
+	SPS_INFO("BAM_REVISION: 0x%x\n", bam_revision);
+	SPS_INFO("    REVISION: 0x%x\n", bam_rev_num);
+	SPS_INFO("    NUM_EES: %d\n", bam_rev_ee_num);
+	SPS_INFO("BAM_SW_REVISION: 0x%x\n", bam_sw_rev);
+	SPS_INFO("BAM_NUM_PIPES: %d\n", bam_num_pipes);
+	SPS_INFO("    NUM_PIPES: %d\n", bam_pipe_num);
+	SPS_INFO("BAM_DESC_CNT_TRSHLD: 0x%x\n", bam_desc_cnt_trshld);
+	SPS_INFO("    DESC_CNT_TRSHLD: 0x%x (%d)\n", bam_desc_cnt_trd_val,
+			bam_desc_cnt_trd_val);
+
+	SPS_INFO("BAM_IRQ_EN: 0x%x\n", bam_irq_en);
+	SPS_INFO("BAM_IRQ_STTS: 0x%x\n", bam_irq_stts);
+
+	if (ee < BAM_MAX_EES) {
+		SPS_INFO("BAM_IRQ_SRCS_EE(%d): 0x%x\n", ee, bam_irq_src_ee);
+		SPS_INFO("BAM_IRQ_SRCS_MSK_EE(%d): 0x%x\n", ee, bam_irq_msk_ee);
+		SPS_INFO("BAM_IRQ_SRCS_UNMASKED_EE(%d): 0x%x\n", ee,
+				bam_irq_unmsk_ee);
+	}
+
+	SPS_INFO("BAM_AHB_MASTER_ERR_CTRLS: 0x%x\n", bam_ahb_err_ctrl);
+	SPS_INFO("BAM_AHB_MASTER_ERR_ADDR: 0x%x\n", bam_ahb_err_addr);
+	SPS_INFO("BAM_AHB_MASTER_ERR_DATA: 0x%x\n", bam_ahb_err_data);
+
+	SPS_INFO("BAM_CNFG_BITS: 0x%x\n", bam_cnfg_bits);
+	SPS_INFO("BAM_TIMER: 0x%x\n", bam_timer);
+	SPS_INFO("BAM_TIMER_CTRL: 0x%x\n", bam_timer_ctrl);
+
+	SPS_INFO("\nsps:<bam-end> --- BAM-level registers ---\n\n");
 }
 
 /* output the content of selected BAM pipe registers */
@@ -1289,68 +1352,205 @@
 	void *base = virt_addr;
 	u32 pipe = pipe_index;
 
+	u32 p_ctrl;
+	u32 p_sys_mode;
+	u32 p_direction;
+	u32 p_lock_group = 0;
+
+	u32 p_irq_en;
+	u32 p_irq_stts;
+	u32 p_irq_stts_eot;
+	u32 p_irq_stts_int;
+
+	u32 p_prd_sdbd;
+	u32 p_bytes_free;
+	u32 p_prd_ctrl;
+	u32 p_prd_toggle;
+	u32 p_prd_sb_updated;
+
+	u32 p_con_sdbd;
+	u32 p_bytes_avail;
+	u32 p_con_ctrl;
+	u32 p_con_toggle;
+	u32 p_con_ack_toggle;
+	u32 p_con_ack_toggle_r;
+	u32 p_con_wait_4_ack;
+	u32 p_con_sb_updated;
+
+	u32 p_sw_offset;
+	u32 p_read_pointer;
+	u32 p_evnt_reg;
+	u32 p_write_pointer;
+
+	u32 p_evnt_dest;
+	u32 p_desc_fifo_addr;
+	u32 p_desc_fifo_size;
+	u32 p_data_fifo_addr;
+	u32 p_data_fifo_size;
+	u32 p_fifo_sizes;
+
+	u32 p_evnt_trd;
+	u32 p_evnt_trd_val;
+
+	u32 p_retr_ct;
+	u32 p_retr_offset;
+	u32 p_si_ct;
+	u32 p_si_offset;
+	u32 p_df_ct = 0;
+	u32 p_df_offset = 0;
+	u32 p_au_ct1;
+	u32 p_psm_ct2;
+	u32 p_psm_ct3;
+	u32 p_psm_ct4;
+	u32 p_psm_ct5;
+
+	u32 p_timer;
+	u32 p_timer_ctrl;
+
 	if (base == NULL)
 		return;
 
-	SPS_INFO("\nsps:----- Registers of Pipe %d -----\n", pipe);
+	p_ctrl = bam_read_reg(base, P_CTRL(pipe));
+	p_sys_mode = bam_read_reg_field(base, P_CTRL(pipe), P_SYS_MODE);
+	p_direction = bam_read_reg_field(base, P_CTRL(pipe), P_DIRECTION);
 
-	SPS_INFO("BAM_P_CTRL: 0x%x\n"
-		"BAM_P_SYS_MODE: %d\n"
-		"BAM_P_DIRECTION: %d\n"
+	p_irq_en = bam_read_reg(base, P_IRQ_EN(pipe));
+	p_irq_stts = bam_read_reg(base, P_IRQ_STTS(pipe));
+	p_irq_stts_eot = bam_read_reg_field(base, P_IRQ_STTS(pipe),
+					P_IRQ_STTS_P_TRNSFR_END_IRQ);
+	p_irq_stts_int = bam_read_reg_field(base, P_IRQ_STTS(pipe),
+					P_IRQ_STTS_P_PRCSD_DESC_IRQ);
+
+	p_prd_sdbd = bam_read_reg(base, P_PRDCR_SDBND(pipe));
+	p_bytes_free = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+					P_PRDCR_SDBNDn_BAM_P_BYTES_FREE);
+	p_prd_ctrl = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+					P_PRDCR_SDBNDn_BAM_P_CTRL);
+	p_prd_toggle = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+					P_PRDCR_SDBNDn_BAM_P_TOGGLE);
+	p_prd_sb_updated = bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+					P_PRDCR_SDBNDn_BAM_P_SB_UPDATED);
+	p_con_sdbd = bam_read_reg(base, P_CNSMR_SDBND(pipe));
+	p_bytes_avail = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL);
+	p_con_ctrl = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_CTRL);
+	p_con_toggle = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_TOGGLE);
+	p_con_ack_toggle = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_ACK_TOGGLE);
+	p_con_ack_toggle_r = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_ACK_TOGGLE_R);
+	p_con_wait_4_ack = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_WAIT_4_ACK);
+	p_con_sb_updated = bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_SB_UPDATED);
+
+	p_sw_offset = bam_read_reg(base, P_SW_OFSTS(pipe));
+	p_read_pointer = bam_read_reg_field(base, P_SW_OFSTS(pipe),
+						SW_DESC_OFST);
+	p_evnt_reg = bam_read_reg(base, P_EVNT_REG(pipe));
+	p_write_pointer = bam_read_reg_field(base, P_EVNT_REG(pipe),
+						P_DESC_FIFO_PEER_OFST);
+
+	p_evnt_dest = bam_read_reg(base, P_EVNT_DEST_ADDR(pipe));
+	p_desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR(pipe));
+	p_desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES(pipe),
+						P_DESC_FIFO_SIZE);
+	p_data_fifo_addr = bam_read_reg(base, P_DATA_FIFO_ADDR(pipe));
+	p_data_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES(pipe),
+						P_DATA_FIFO_SIZE);
+	p_fifo_sizes = bam_read_reg(base, P_FIFO_SIZES(pipe));
+
+	p_evnt_trd = bam_read_reg(base, P_EVNT_GEN_TRSHLD(pipe));
+	p_evnt_trd_val = bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
+					P_EVNT_GEN_TRSHLD_P_TRSHLD);
+
+	p_retr_ct = bam_read_reg(base, P_RETR_CNTXT(pipe));
+	p_retr_offset = bam_read_reg_field(base, P_RETR_CNTXT(pipe),
+					P_RETR_CNTXT_RETR_DESC_OFST);
+	p_si_ct = bam_read_reg(base, P_SI_CNTXT(pipe));
+	p_si_offset = bam_read_reg_field(base, P_SI_CNTXT(pipe),
+					P_SI_CNTXT_SI_DESC_OFST);
+	p_au_ct1 = bam_read_reg(base, P_AU_PSM_CNTXT_1(pipe));
+	p_psm_ct2 = bam_read_reg(base, P_PSM_CNTXT_2(pipe));
+	p_psm_ct3 = bam_read_reg(base, P_PSM_CNTXT_3(pipe));
+	p_psm_ct4 = bam_read_reg(base, P_PSM_CNTXT_4(pipe));
+	p_psm_ct5 = bam_read_reg(base, P_PSM_CNTXT_5(pipe));
+
+	p_timer = bam_read_reg(base, P_TIMER(pipe));
+	p_timer_ctrl = bam_read_reg(base, P_TIMER_CTRL(pipe));
+
 #ifdef CONFIG_SPS_SUPPORT_NDP_BAM
-		"BAM_P_LOCK_GROUP: 0x%x (%d)\n"
+	p_lock_group = bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP);
+	p_df_ct = bam_read_reg(base, P_DF_CNTXT(pipe));
+	p_df_offset = bam_read_reg_field(base, P_DF_CNTXT(pipe),
+					P_DF_CNTXT_DF_DESC_OFST);
 #endif
-		"BAM_P_EE: %d\n"
-		"BAM_P_IRQ_STTS: 0x%x\n"
-		"BAM_P_IRQ_STTS_P_TRNSFR_END_IRQ: 0x%x\n"
-		"BAM_P_IRQ_STTS_P_PRCSD_DESC_IRQ: 0x%x\n"
-		"BAM_P_IRQ_EN: 0x%x\n"
-		"BAM_P_PRDCR_SDBNDn_BAM_P_BYTES_FREE: 0x%x (%d)\n"
-		"BAM_P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL: 0x%x (%d)\n"
-		"BAM_P_SW_DESC_OFST: 0x%x\n"
-		"BAM_P_DESC_FIFO_PEER_OFST: 0x%x\n"
-		"BAM_P_EVNT_DEST_ADDR: 0x%x\n"
-		"BAM_P_DESC_FIFO_ADDR: 0x%x\n"
-		"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n"
-		"BAM_P_DATA_FIFO_ADDR: 0x%x\n"
-		"BAM_P_DATA_FIFO_SIZE: 0x%x (%d)\n"
-		"BAM_P_EVNT_GEN_TRSHLD: 0x%x (%d)\n",
-		bam_read_reg(base, P_CTRL(pipe)),
-		bam_read_reg_field(base, P_CTRL(pipe), P_SYS_MODE),
-		bam_read_reg_field(base, P_CTRL(pipe), P_DIRECTION),
-#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
-		bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
-		bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
-#endif
-		bam_read_reg_field(base, P_TRUST_REG(pipe), BAM_P_EE),
-		bam_read_reg(base, P_IRQ_STTS(pipe)),
-		bam_read_reg_field(base, P_IRQ_STTS(pipe),
-					P_IRQ_STTS_P_TRNSFR_END_IRQ),
-		bam_read_reg_field(base, P_IRQ_STTS(pipe),
-					P_IRQ_STTS_P_PRCSD_DESC_IRQ),
-		bam_read_reg(base, P_IRQ_EN(pipe)),
-		bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
-					P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
-		bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
-					P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
-		bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
-					P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
-		bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
-					P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
-		bam_read_reg_field(base, P_SW_OFSTS(pipe), SW_DESC_OFST),
-		bam_read_reg_field(base, P_EVNT_REG(pipe),
-					P_DESC_FIFO_PEER_OFST),
-		bam_read_reg(base, P_EVNT_DEST_ADDR(pipe)),
-		bam_read_reg(base, P_DESC_FIFO_ADDR(pipe)),
-		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
-		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
-		bam_read_reg(base, P_DATA_FIFO_ADDR(pipe)),
-		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
-		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
-		bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
-					P_EVNT_GEN_TRSHLD_P_TRSHLD),
-		bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
-					P_EVNT_GEN_TRSHLD_P_TRSHLD));
+
+	SPS_INFO("\nsps:<pipe-begin> --- Registers of Pipe %d ---\n\n", pipe);
+
+	SPS_INFO("BAM_P_CTRL: 0x%x\n", p_ctrl);
+	SPS_INFO("    SYS_MODE: %d\n", p_sys_mode);
+	if (p_direction)
+		SPS_INFO("    DIRECTION:%d->Producer\n", p_direction);
+	else
+		SPS_INFO("    DIRECTION:%d->Consumer\n", p_direction);
+	SPS_INFO("    LOCK_GROUP: 0x%x (%d)\n", p_lock_group, p_lock_group);
+
+	SPS_INFO("BAM_P_IRQ_EN: 0x%x\n", p_irq_en);
+	SPS_INFO("BAM_P_IRQ_STTS: 0x%x\n", p_irq_stts);
+	SPS_INFO("    TRNSFR_END_IRQ(EOT): 0x%x\n", p_irq_stts_eot);
+	SPS_INFO("    PRCSD_DESC_IRQ(INT): 0x%x\n", p_irq_stts_int);
+
+	SPS_INFO("BAM_P_PRDCR_SDBND: 0x%x\n", p_prd_sdbd);
+	SPS_INFO("    BYTES_FREE: 0x%x (%d)\n", p_bytes_free, p_bytes_free);
+	SPS_INFO("    CTRL: 0x%x\n", p_prd_ctrl);
+	SPS_INFO("    TOGGLE: %d\n", p_prd_toggle);
+	SPS_INFO("    SB_UPDATED: %d\n", p_prd_sb_updated);
+	SPS_INFO("BAM_P_CNSMR_SDBND: 0x%x\n", p_con_sdbd);
+	SPS_INFO("    WAIT_4_ACK: %d\n", p_con_wait_4_ack);
+	SPS_INFO("    BYTES_AVAIL: 0x%x (%d)\n", p_bytes_avail, p_bytes_avail);
+	SPS_INFO("    CTRL: 0x%x\n", p_con_ctrl);
+	SPS_INFO("    TOGGLE: %d\n", p_con_toggle);
+	SPS_INFO("    ACK_TOGGLE: %d\n", p_con_ack_toggle);
+	SPS_INFO("    ACK_TOGGLE_R: %d\n", p_con_ack_toggle_r);
+	SPS_INFO("    SB_UPDATED: %d\n", p_con_sb_updated);
+
+	SPS_INFO("BAM_P_SW_DESC_OFST: 0x%x\n", p_sw_offset);
+	SPS_INFO("    SW_DESC_OFST: 0x%x\n", p_read_pointer);
+	SPS_INFO("BAM_P_EVNT_REG: 0x%x\n", p_evnt_reg);
+	SPS_INFO("    DESC_FIFO_PEER_OFST: 0x%x\n", p_write_pointer);
+
+	SPS_INFO("BAM_P_RETR_CNTXT: 0x%x\n", p_retr_ct);
+	SPS_INFO("    RETR_OFFSET: 0x%x\n", p_retr_offset);
+	SPS_INFO("BAM_P_SI_CNTXT: 0x%x\n", p_si_ct);
+	SPS_INFO("    SI_OFFSET: 0x%x\n", p_si_offset);
+	SPS_INFO("BAM_P_DF_CNTXT: 0x%x\n", p_df_ct);
+	SPS_INFO("    DF_OFFSET: 0x%x\n", p_df_offset);
+
+	SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n", p_desc_fifo_addr);
+	SPS_INFO("BAM_P_DATA_FIFO_ADDR: 0x%x\n", p_data_fifo_addr);
+	SPS_INFO("BAM_P_FIFO_SIZES: 0x%x\n", p_fifo_sizes);
+	SPS_INFO("    DESC_FIFO_SIZE: 0x%x (%d)\n", p_desc_fifo_size,
+							p_desc_fifo_size);
+	SPS_INFO("    DATA_FIFO_SIZE: 0x%x (%d)\n", p_data_fifo_size,
+							p_data_fifo_size);
+
+	SPS_INFO("BAM_P_EVNT_DEST_ADDR: 0x%x\n", p_evnt_dest);
+	SPS_INFO("BAM_P_EVNT_GEN_TRSHLD: 0x%x\n", p_evnt_trd);
+	SPS_INFO("    EVNT_GEN_TRSHLD: 0x%x (%d)\n", p_evnt_trd_val,
+							p_evnt_trd_val);
+
+	SPS_INFO("BAM_P_AU_PSM_CNTXT_1: 0x%x\n", p_au_ct1);
+	SPS_INFO("BAM_P_PSM_CNTXT_2: 0x%x\n", p_psm_ct2);
+	SPS_INFO("BAM_P_PSM_CNTXT_3: 0x%x\n", p_psm_ct3);
+	SPS_INFO("BAM_P_PSM_CNTXT_4: 0x%x\n", p_psm_ct4);
+	SPS_INFO("BAM_P_PSM_CNTXT_5: 0x%x\n", p_psm_ct5);
+	SPS_INFO("BAM_P_TIMER: 0x%x\n", p_timer);
+	SPS_INFO("BAM_P_TIMER_CTRL: 0x%x\n", p_timer_ctrl);
+
+	SPS_INFO("\nsps:<pipe-end> --- Registers of Pipe %d ---\n\n", pipe);
 }
 
 /* output descriptor FIFO of a pipe */
@@ -1362,6 +1562,7 @@
 	u32 desc_fifo_size;
 	u32 *desc_fifo;
 	int i;
+	char desc_info[MAX_MSG_LEN];
 
 	if (base == NULL)
 		return;
@@ -1380,7 +1581,8 @@
 		return;
 	}
 
-	SPS_INFO("\nsps:----- descriptor FIFO of Pipe %d -----\n", pipe);
+	SPS_INFO("\nsps:<desc-begin> --- descriptor FIFO of Pipe %d -----\n\n",
+			pipe);
 
 	SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n"
 		"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n",
@@ -1428,17 +1630,49 @@
 		if (desc_fifo_size > current_desc + size / 2)
 			end = current_desc + size / 2;
 
-		SPS_INFO("------------- begin of partial FIFO -------------\n");
+		SPS_INFO("------------ begin of partial FIFO ------------\n\n");
 
-		for (i = begin; i < end; i += 0x10)
-			SPS_INFO("addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x.\n",
+		SPS_INFO("desc addr; desc content; desc flags\n");
+		for (i = begin; i < end; i += 0x8) {
+			u32 offset;
+			u32 flags = desc_fifo[(i / 4) + 1] >> 16;
+
+			memset(desc_info, 0, sizeof(desc_info));
+			offset = scnprintf(desc_info, 40, "0x%x: 0x%x, 0x%x: ",
 				desc_fifo_addr + i,
-				desc_fifo[i / 4], desc_fifo[(i / 4) + 1],
-				desc_fifo[(i / 4) + 2], desc_fifo[(i / 4) + 3]);
+				desc_fifo[i / 4], desc_fifo[(i / 4) + 1]);
 
-		SPS_INFO("-------------  end of partial FIFO  -------------\n");
+			if (flags & SPS_IOVEC_FLAG_INT)
+				offset += scnprintf(desc_info + offset, 5,
+							"INT ");
+			if (flags & SPS_IOVEC_FLAG_EOT)
+				offset += scnprintf(desc_info + offset, 5,
+							"EOT ");
+			if (flags & SPS_IOVEC_FLAG_EOB)
+				offset += scnprintf(desc_info + offset, 5,
+							"EOB ");
+			if (flags & SPS_IOVEC_FLAG_NWD)
+				offset += scnprintf(desc_info + offset, 5,
+							"NWD ");
+			if (flags & SPS_IOVEC_FLAG_CMD)
+				offset += scnprintf(desc_info + offset, 5,
+							"CMD ");
+			if (flags & SPS_IOVEC_FLAG_LOCK)
+				offset += scnprintf(desc_info + offset, 5,
+							"LCK ");
+			if (flags & SPS_IOVEC_FLAG_UNLOCK)
+				offset += scnprintf(desc_info + offset, 5,
+							"UNL ");
+			if (flags & SPS_IOVEC_FLAG_IMME)
+				offset += scnprintf(desc_info + offset, 5,
+							"IMM ");
+
+			SPS_INFO("%s\n", desc_info);
+		}
+
+		SPS_INFO("\n------------  end of partial FIFO  ------------\n");
 	} else {
-		SPS_INFO("----------------- begin of FIFO -----------------\n");
+		SPS_INFO("---------------- begin of FIFO ----------------\n\n");
 
 		for (i = 0; i < desc_fifo_size; i += 0x10)
 			SPS_INFO("addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x.\n",
@@ -1446,8 +1680,11 @@
 				desc_fifo[i / 4], desc_fifo[(i / 4) + 1],
 				desc_fifo[(i / 4) + 2], desc_fifo[(i / 4) + 3]);
 
-		SPS_INFO("-----------------  end of FIFO  -----------------\n");
+		SPS_INFO("\n----------------  end of FIFO  ----------------\n");
 	}
+
+	SPS_INFO("\nsps:<desc-end> --- descriptor FIFO of Pipe %d -----\n\n",
+			pipe);
 }
 
 /* output BAM_TEST_BUS_REG with specified TEST_BUS_SEL */
@@ -1476,14 +1713,18 @@
 						BAM_TESTBUS_SEL));
 	}
 
+	SPS_INFO("\nsps:<testbus-begin> --- BAM TEST_BUS dump -----\n\n");
+
 	/* output other selections */
 	for (i = 0; i < size; i++) {
 		bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
 					test_bus_selection[i]);
 
-		SPS_INFO("sps:bam 0x%x(va);TEST_BUS_REG:0x%x;TEST_BUS_SEL:0x%x",
-			(u32) base, bam_read_reg(base, TEST_BUS_REG),
+		SPS_INFO("sps:TEST_BUS_REG:0x%x\t  TEST_BUS_SEL:0x%x\n",
+			bam_read_reg(base, TEST_BUS_REG),
 			bam_read_reg_field(base, TEST_BUS_SEL,
 					BAM_TESTBUS_SEL));
 	}
+
+	SPS_INFO("\nsps:<testbus-end> --- BAM TEST_BUS dump -----\n\n");
 }
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index b34f9dc..6f2e2a4 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -325,7 +325,7 @@
 		print_bam_reg(vir_addr);
 		break;
 	case 3: /* output selected BAM-level registers */
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		break;
 	case 4: /* output selected registers of all pipes */
 		for (i = 0; i < num_pipes; i++)
@@ -401,21 +401,14 @@
 	case 91: /* output testbus register, BAM global regisers
 			and registers of all pipes */
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_selected_reg(vir_addr, i);
 		break;
 	case 92: /* output testbus register, BAM global regisers
 			and registers of selected pipes */
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (bam_pipe_sel & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -425,11 +418,7 @@
 		if (desc_option == 0)
 			desc_option = 1;
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (bam_pipe_sel & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -443,11 +432,9 @@
 		if (desc_option == 0)
 			desc_option = 1;
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i)) {
-				print_bam_pipe_reg(vir_addr, i);
 				print_bam_pipe_selected_reg(vir_addr, i);
 				print_bam_pipe_desc_fifo(vir_addr, i,
 							desc_option);
@@ -456,11 +443,7 @@
 	case 95: /* output registers and desc FIFOs
 			of selected pipes: format 1 */
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (bam_pipe_sel & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -471,11 +454,9 @@
 	case 96: /* output registers and desc FIFOs
 			of selected pipes: format 2 */
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i)) {
-				print_bam_pipe_reg(vir_addr, i);
 				print_bam_pipe_selected_reg(vir_addr, i);
 				print_bam_pipe_desc_fifo(vir_addr, i, 0);
 			}
@@ -483,11 +464,7 @@
 	case 97: /* output registers, desc FIFOs and partial data blocks
 			of selected pipes: format 1 */
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (bam_pipe_sel & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -501,11 +478,9 @@
 	case 98: /* output registers, desc FIFOs and partial data blocks
 			of selected pipes: format 2 */
 		print_bam_test_bus_reg(vir_addr, testbus_sel);
-		print_bam_reg(vir_addr);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (bam_pipe_sel & (1UL << i)) {
-				print_bam_pipe_reg(vir_addr, i);
 				print_bam_pipe_selected_reg(vir_addr, i);
 				print_bam_pipe_desc_fifo(vir_addr, i, 0);
 				print_bam_pipe_desc_fifo(vir_addr, i, 100);
@@ -516,7 +491,7 @@
 		print_bam_reg(vir_addr);
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_selected_reg(vir_addr, i);
 		for (i = 0; i < num_pipes; i++)
@@ -674,7 +649,7 @@
 
 /* Get the debug info of BAM registers and descriptor FIFOs */
 int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
-		u32 tb_sel, u8 desc_sel)
+		u32 tb_sel, u32 desc_sel)
 {
 	int res = 0;
 	struct sps_bam *bam;
@@ -700,6 +675,8 @@
 	vir_addr = bam->base;
 	num_pipes = bam->props.num_pipes;
 
+	SPS_INFO("sps:<bam-addr> dump BAM:0x%x.\n", bam->props.phys_addr);
+
 	switch (option) {
 	case 1: /* output all registers of this BAM */
 		print_bam_reg(vir_addr);
@@ -710,7 +687,7 @@
 		print_bam_reg(vir_addr);
 		break;
 	case 3: /* output selected BAM-level registers */
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		break;
 	case 4: /* output selected registers of all pipes */
 		for (i = 0; i < num_pipes; i++)
@@ -784,21 +761,14 @@
 	case 91: /* output testbus register, BAM global regisers
 			and registers of all pipes */
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_selected_reg(vir_addr, i);
 		break;
 	case 92: /* output testbus register, BAM global regisers
 			and registers of selected pipes */
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (para & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -808,11 +778,7 @@
 		if (desc_sel == 0)
 			desc_sel = 1;
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (para & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -826,11 +792,9 @@
 		if (desc_sel == 0)
 			desc_sel = 1;
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i)) {
-				print_bam_pipe_reg(vir_addr, i);
 				print_bam_pipe_selected_reg(vir_addr, i);
 				print_bam_pipe_desc_fifo(vir_addr, i,
 							desc_sel);
@@ -839,11 +803,7 @@
 	case 95: /* output registers and desc FIFOs
 			of selected pipes: format 1 */
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (para & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -854,11 +814,9 @@
 	case 96: /* output registers and desc FIFOs
 			of selected pipes: format 2 */
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i)) {
-				print_bam_pipe_reg(vir_addr, i);
 				print_bam_pipe_selected_reg(vir_addr, i);
 				print_bam_pipe_desc_fifo(vir_addr, i, 0);
 			}
@@ -866,11 +824,7 @@
 	case 97: /* output registers, desc FIFOs and partial data blocks
 			of selected pipes: format 1 */
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		for (i = 0; i < num_pipes; i++)
-			if (para & (1UL << i))
-				print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i))
 				print_bam_pipe_selected_reg(vir_addr, i);
@@ -884,11 +838,9 @@
 	case 98: /* output registers, desc FIFOs and partial data blocks
 			of selected pipes: format 2 */
 		print_bam_test_bus_reg(vir_addr, tb_sel);
-		print_bam_reg(vir_addr);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			if (para & (1UL << i)) {
-				print_bam_pipe_reg(vir_addr, i);
 				print_bam_pipe_selected_reg(vir_addr, i);
 				print_bam_pipe_desc_fifo(vir_addr, i, 0);
 				print_bam_pipe_desc_fifo(vir_addr, i, 100);
@@ -899,7 +851,7 @@
 		print_bam_reg(vir_addr);
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_reg(vir_addr, i);
-		print_bam_selected_reg(vir_addr);
+		print_bam_selected_reg(vir_addr, bam->props.ee);
 		for (i = 0; i < num_pipes; i++)
 			print_bam_pipe_selected_reg(vir_addr, i);
 		for (i = 0; i < num_pipes; i++)
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 5ad281d..31d1a78 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -403,8 +403,9 @@
 	}
 
 	dev->state |= BAM_STATE_ENABLED;
-	SPS_INFO("sps:BAM 0x%x enabled: ver:0x%x, number of pipes:%d",
-		BAM_ID(dev), dev->version, dev->props.num_pipes);
+	SPS_INFO("sps:BAM 0x%x (va:0x%x) enabled: ver:0x%x, number of pipes:%d",
+		BAM_ID(dev), (u32) dev->base, dev->version,
+		dev->props.num_pipes);
 	return 0;
 }
 
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 5b70fb0..8da3b40 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -40,6 +40,8 @@
 /* "Clear" value for the connection parameter struct */
 #define SPSRM_CLEAR     0xcccccccc
 
+#define MAX_MSG_LEN 80
+
 extern u32 d_type;
 
 #ifdef CONFIG_DEBUG_FS
@@ -48,25 +50,28 @@
 extern u8 debug_level_option;
 extern u8 print_limit_option;
 
-#define MAX_MSG_LEN 80
 #define SPS_DEBUGFS(msg, args...) do {					\
 		char buf[MAX_MSG_LEN];		\
 		snprintf(buf, MAX_MSG_LEN, msg"\n", ##args);	\
 		sps_debugfs_record(buf);	\
 	} while (0)
 #define SPS_ERR(msg, args...) do {					\
-		if (unlikely(print_limit_option > 2))	\
-			pr_err_ratelimited(msg, ##args);	\
-		else	\
-			pr_err(msg, ##args);	\
+		if (logging_option != 1) {	\
+			if (unlikely(print_limit_option > 2))	\
+				pr_err_ratelimited(msg, ##args);	\
+			else	\
+				pr_err(msg, ##args);	\
+		}	\
 		if (unlikely(debugfs_record_enabled))	\
 			SPS_DEBUGFS(msg, ##args);	\
 	} while (0)
 #define SPS_INFO(msg, args...) do {					\
-		if (unlikely(print_limit_option > 1))	\
-			pr_info_ratelimited(msg, ##args);	\
-		else	\
-			pr_info(msg, ##args);	\
+		if (logging_option != 1) {	\
+			if (unlikely(print_limit_option > 1))	\
+				pr_info_ratelimited(msg, ##args);	\
+			else	\
+				pr_info(msg, ##args);	\
+		}	\
 		if (unlikely(debugfs_record_enabled))	\
 			SPS_DEBUGFS(msg, ##args);	\
 	} while (0)
@@ -192,7 +197,7 @@
 void print_bam_pipe_reg(void *, u32);
 
 /* output the content of selected BAM-level registers */
-void print_bam_selected_reg(void *);
+void print_bam_selected_reg(void *, u32);
 
 /* output the content of selected BAM pipe registers */
 void print_bam_pipe_selected_reg(void *, u32);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index a2701ce..91aaf3c 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -170,6 +170,9 @@
 	int			disable_flat_portion_ocv;
 	int			ocv_dis_high_soc;
 	int			ocv_dis_low_soc;
+	int			high_ocv_correction_limit_uv;
+	int			low_ocv_correction_limit_uv;
+	int			hold_soc_est;
 	int			prev_vbat_batt_terminal_uv;
 	int			vbatt_cutoff_count;
 	int			low_voltage_detect;
@@ -1861,6 +1864,7 @@
 	int m = 0;
 	int rc = 0;
 	int delta_ocv_uv_limit = 0;
+	int correction_limit_uv = 0;
 
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
@@ -1905,17 +1909,13 @@
 
 	/*
 	 * do not adjust
-	 * if soc is same as what bms calculated
-	 * if soc_est is between 45 and 25, this is the flat portion of the
-	 * curve where soc_est is not so accurate. We generally don't want to
-	 * adjust when soc_est is inaccurate except for the cases when soc is
-	 * way far off (higher than 50 or lesser than 20).
-	 * Also don't adjust soc if it is above 90 becuase we might pull it low
+	 * if soc_est is same as what bms calculated
+	 * OR if soc_est > 15
+	 * OR if soc it is above 90 because we might pull it low
 	 * and  cause a bad user experience
 	 */
 	if (soc_est == soc
-		|| (is_between(45, chip->adjust_soc_low_threshold, soc_est)
-		&& is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+		|| soc_est > 15
 		|| soc >= 90)
 		goto out;
 
@@ -1964,6 +1964,22 @@
 		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
 	}
 
+	if (chip->last_ocv_uv > 3800000)
+		correction_limit_uv = the_chip->high_ocv_correction_limit_uv;
+	else
+		correction_limit_uv = the_chip->low_ocv_correction_limit_uv;
+
+	if (abs(delta_ocv_uv) > correction_limit_uv) {
+		pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+				correction_limit_uv);
+
+		if (delta_ocv_uv > 0)
+			delta_ocv_uv = correction_limit_uv;
+		else
+			delta_ocv_uv = -1 * correction_limit_uv;
+		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+	}
+
 	chip->last_ocv_uv -= delta_ocv_uv;
 
 	if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1980,7 +1996,7 @@
 	 * if soc_new is ZERO force it higher so that phone doesnt report soc=0
 	 * soc = 0 should happen only when soc_est == 0
 	 */
-	if (soc_new == 0 && soc_est != 0)
+	if (soc_new == 0 && soc_est >= the_chip->hold_soc_est)
 		soc_new = 1;
 
 	soc = soc_new;
@@ -2479,9 +2495,18 @@
 
 	/* last_soc < soc  ... scale and catch up */
 	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
-		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+			soc = scale_soc_while_chg(chip, delta_time_us,
+							soc, last_soc);
 
-	last_soc = soc;
+	/* restrict soc to 1% change */
+	if (last_soc != -EINVAL) {
+		if (soc < last_soc && soc != 0)
+			soc = last_soc - 1;
+		if (soc > last_soc && soc != 100)
+			soc = last_soc + 1;
+	}
+
+	last_soc = bound_soc(soc);
 	backup_soc_and_iavg(chip, batt_temp, last_soc);
 	pr_debug("Reported SOC = %d\n", last_soc);
 	chip->t_soc_queried = now;
@@ -2986,6 +3011,7 @@
 	GET_VBAT_VSENSE_SIMULTANEOUS,
 	STOP_OCV,
 	START_OCV,
+	SET_OCV,
 };
 
 static int test_batt_temp = 5;
@@ -3227,6 +3253,8 @@
 				(void *)STOP_OCV, &calc_fops);
 	debugfs_create_file("start_ocv", 0644, chip->dent,
 				(void *)START_OCV, &calc_fops);
+	debugfs_create_file("set_ocv", 0644, chip->dent,
+				(void *)SET_OCV, &calc_fops);
 
 	debugfs_create_file("simultaneous", 0644, chip->dent,
 			(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
@@ -3372,6 +3400,11 @@
 	chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
 	chip->ocv_dis_low_soc = pdata->ocv_dis_low_soc;
 
+	chip->high_ocv_correction_limit_uv
+					= pdata->high_ocv_correction_limit_uv;
+	chip->low_ocv_correction_limit_uv = pdata->low_ocv_correction_limit_uv;
+	chip->hold_soc_est = pdata->hold_soc_est;
+
 	chip->alarm_low_mv = pdata->alarm_low_mv;
 	chip->alarm_high_mv = pdata->alarm_high_mv;
 	chip->low_voltage_detect = pdata->low_voltage_detect;
@@ -3463,6 +3496,18 @@
 	return 0;
 }
 
+static int pm8921_bms_suspend(struct device *dev)
+{
+	/*
+	 * set the last reported soc to invalid, so that
+	 * next time we resume we don't want to restrict
+	 * the decrease of soc by only 1%
+	 */
+	last_soc = -EINVAL;
+
+	return 0;
+}
+
 static int pm8921_bms_resume(struct device *dev)
 {
 	int rc;
@@ -3490,6 +3535,7 @@
 
 static const struct dev_pm_ops pm8921_bms_pm_ops = {
 	.resume		= pm8921_bms_resume,
+	.suspend	= pm8921_bms_suspend,
 };
 
 static struct platform_driver pm8921_bms_driver = {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 08cf71e..cb5be3d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -486,7 +486,7 @@
 
 static int calib_vadc(struct qpnp_bms_chip *chip)
 {
-	int rc;
+	int rc, raw_0625, raw_1250;
 	struct qpnp_vadc_result result;
 
 	rc = qpnp_vadc_read(REF_625MV, &result);
@@ -494,16 +494,19 @@
 		pr_debug("vadc read failed with rc = %d\n", rc);
 		return rc;
 	}
-	chip->vadc_v0625 = result.physical;
+	raw_0625 = result.adc_code;
 
 	rc = qpnp_vadc_read(REF_125V, &result);
 	if (rc) {
 		pr_debug("vadc read failed with rc = %d\n", rc);
 		return rc;
 	}
-	chip->vadc_v1250 = result.physical;
-	pr_debug("vadc calib: 0625 = %d, 1250 = %d\n",
-			chip->vadc_v0625, chip->vadc_v1250);
+	raw_1250 = result.adc_code;
+	chip->vadc_v0625 = vadc_reading_to_uv(raw_0625);
+	chip->vadc_v1250 = vadc_reading_to_uv(raw_1250);
+	pr_debug("vadc calib: 0625 = %d raw (%d uv), 1250 = %d raw (%d uv)\n",
+			raw_0625, chip->vadc_v0625,
+			raw_1250, chip->vadc_v1250);
 	return 0;
 }
 
@@ -1608,10 +1611,9 @@
 	pr_debug("SOC before adjustment = %d\n", soc);
 	new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
 
-	/* clamp soc due to BMS HW inaccuracies in pm8941v2.0 */
-	if (chip->revision1 == 0 && chip->revision2 == 0)
-		new_calculated_soc = clamp_soc_based_on_voltage(chip,
-						new_calculated_soc);
+	/* always clamp soc due to BMS hw/sw immaturities */
+	new_calculated_soc = clamp_soc_based_on_voltage(chip,
+					new_calculated_soc);
 
 done_calculating:
 	if (new_calculated_soc != chip->calculated_soc
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 35d8df9..b479477 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1025,13 +1025,15 @@
 
 	/* Only honour requests while USB is present */
 	if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+		chip->usb_psy->get_property(chip->usb_psy,
+			  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
 		if (ret.intval <= 2 && !chip->use_default_batt_values &&
 						get_prop_batt_present(chip)) {
-			qpnp_chg_usb_suspend_enable(chip, 1);
 			qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+			qpnp_chg_usb_suspend_enable(chip, 1);
 		} else {
-			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			qpnp_chg_usb_suspend_enable(chip, 0);
+			qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 		}
 	}
 
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 71554ed..9b2f554 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -64,60 +64,6 @@
 			printk(x);			\
 	} while (0)
 
-
-static int can_use_cma_pages(struct zone *zone, gfp_t gfp_mask)
-{
-	int can_use = 0;
-	int mtype = allocflags_to_migratetype(gfp_mask);
-	int i = 0;
-	int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
-
-	if (is_migrate_cma(mtype)) {
-		can_use = 1;
-	} else {
-		for (i = 0;; i++) {
-			int fallbacktype = mtype_fallbacks[i];
-
-			if (is_migrate_cma(fallbacktype)) {
-				can_use = 1;
-				break;
-			}
-
-			if (fallbacktype == MIGRATE_RESERVE)
-				break;
-		}
-	}
-	return can_use;
-}
-
-
-static int nr_free_zone_pages(struct zone *zone, gfp_t gfp_mask)
-{
-	int sum = zone_page_state(zone, NR_FREE_PAGES);
-
-	if (!can_use_cma_pages(zone, gfp_mask))
-		sum -= zone_page_state(zone, NR_FREE_CMA_PAGES);
-
-	return sum;
-}
-
-
-static int nr_free_pages(gfp_t gfp_mask)
-{
-	struct zoneref *z;
-	struct zone *zone;
-	int sum = 0;
-
-	struct zonelist *zonelist = node_zonelist(numa_node_id(), gfp_mask);
-
-	for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
-		sum += nr_free_zone_pages(zone, gfp_mask);
-	}
-
-	return sum;
-}
-
-
 static int test_task_flag(struct task_struct *p, int flag)
 {
 	struct task_struct *t = p;
@@ -160,15 +106,6 @@
 	other_file = global_page_state(NR_FILE_PAGES) -
 						global_page_state(NR_SHMEM);
 
-	if (nr_to_scan > 0 && other_free > other_file) {
-		/*
-		 * If the number of free pages is going to affect the decision
-		 * of which process is selected then ensure only free pages
-		 * which can satisfy the request are considered.
-		 */
-		other_free = nr_free_pages(sc->gfp_mask);
-	}
-
 	if (lowmem_adj_size < array_size)
 		array_size = lowmem_adj_size;
 	if (lowmem_minfree_size < array_size)
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index c02db14..8b05682 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1330,11 +1330,11 @@
 					channel, scale_type, dt_index);
 	adc_tm->adc->amux_prop->amux_channel = channel;
 	adc_tm->adc->amux_prop->decimation =
-			adc_tm->adc->adc_channels[channel].adc_decimation;
+			adc_tm->adc->adc_channels[dt_index].adc_decimation;
 	adc_tm->adc->amux_prop->hw_settle_time =
-			adc_tm->adc->adc_channels[channel].hw_settle_time;
+			adc_tm->adc->adc_channels[dt_index].hw_settle_time;
 	adc_tm->adc->amux_prop->fast_avg_setup =
-			adc_tm->adc->adc_channels[channel].fast_avg_setup;
+			adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
 	adc_tm->adc->amux_prop->mode_sel =
 		ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
 	adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 4b9dfbf..2dccca8 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -387,7 +387,7 @@
 	unsigned		port_num;
 	enum transport_type	cxport = rmnet_ports[dev->port_num].ctrl_xport;
 	enum transport_type	dxport = rmnet_ports[dev->port_num].data_xport;
-	u8			src_connection_idx, dst_connection_idx;
+	int			src_connection_idx = 0, dst_connection_idx = 0;
 	struct usb_gadget	*gadget = dev->cdev->gadget;
 
 	pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
@@ -439,7 +439,6 @@
 	port_num = rmnet_ports[dev->port_num].data_xport_num;
 
 	switch (dxport) {
-	case USB_GADGET_XPORT_BAM:
 	case USB_GADGET_XPORT_BAM2BAM:
 		src_connection_idx = usb_bam_get_connection_idx(gadget->name,
 			A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
@@ -451,6 +450,7 @@
 			gsmd_ctrl_disconnect(&dev->port, port_num);
 			return ret;
 		}
+	case USB_GADGET_XPORT_BAM:
 		ret = gbam_connect(&dev->port, port_num,
 			dxport, src_connection_idx, dst_connection_idx);
 		if (ret) {
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index a710fef..7fafbc64 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,6 +1,7 @@
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
 mdss-mdp-objs += mdss_mdp_pp.o
 mdss-mdp-objs += mdss_mdp_intf_video.o
+mdss-mdp-objs += mdss_mdp_intf_cmd.o
 mdss-mdp-objs += mdss_mdp_intf_writeback.o
 mdss-mdp-objs += mdss_mdp_rotator.o
 mdss-mdp-objs += mdss_mdp_overlay.o
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index bfcd7ec..faf3e6f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -25,6 +25,7 @@
 #include "mdss.h"
 #include "mdss_panel.h"
 #include "mdss_dsi.h"
+#include "mdss_debug.h"
 
 static unsigned char *mdss_dsi_base;
 
@@ -250,32 +251,6 @@
 	return 0;
 }
 
-static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata)
-{
-	struct mdss_panel_info *pinfo;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-	int ret = 0;
-
-	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);
-	pinfo = &pdata->panel_info;
-
-	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
-
-	ret = ctrl_pdata->off(pdata);
-	if (ret) {
-		pr_err("%s: Panel OFF failed\n", __func__);
-		return ret;
-	}
-
-	return ret;
-}
-
 static void mdss_dsi_put_dt_vreg_data(struct device *dev,
 	struct dss_module_power *module_power)
 {
@@ -443,6 +418,10 @@
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+
+	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+				ctrl_pdata, ctrl_pdata->ndx);
+
 	mdss_dsi_clk_disable(pdata);
 	mdss_dsi_unprepare_clocks(ctrl_pdata);
 
@@ -514,6 +493,10 @@
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+
+	pr_debug("%s+: ctrl=%p ndx=%d\n",
+				__func__, ctrl_pdata, ctrl_pdata->ndx);
+
 	pinfo = &pdata->panel_info;
 
 	ret = mdss_dsi_panel_power_on(pdata, 1);
@@ -597,6 +580,27 @@
 		wmb();
 	}
 
+	pr_debug("%s-:\n", __func__);
+	return 0;
+}
+
+static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	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);
+	mipi  = &pdata->panel_info.mipi;
+
 	ret = ctrl_pdata->on(pdata);
 	if (ret) {
 		pr_err("%s: unable to initialize the panel\n", __func__);
@@ -605,6 +609,34 @@
 
 	mdss_dsi_op_mode_config(mipi->mode, pdata);
 
+	pr_debug("%s-:\n", __func__);
+
+	return ret;
+}
+
+static int mdss_dsi_blank(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	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);
+
+	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+
+	ret = ctrl_pdata->off(pdata);
+	if (ret) {
+		pr_err("%s: Panel OFF failed\n", __func__);
+		return ret;
+	}
+
 	pr_debug("%s-:End\n", __func__);
 	return ret;
 }
@@ -621,33 +653,27 @@
 	}
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+	pr_debug("%s+:event=%d\n", __func__, event);
+
 	switch (event) {
 	case MDSS_EVENT_UNBLANK:
+		rc = mdss_dsi_on(pdata);
 		if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
-			rc = mdss_dsi_on(pdata);
-		} else {
-			pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
-			rc = -EINVAL;
+			rc = mdss_dsi_unblank(pdata);
 		}
 		break;
+	case MDSS_EVENT_PANEL_ON:
+		if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE)
+			rc = mdss_dsi_unblank(pdata);
+		break;
 	case MDSS_EVENT_BLANK:
 		if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) {
-			rc = mdss_dsi_ctrl_unprepare(pdata);
-		} else {
-			pr_debug("%s:event=%d,Unprepare not called.Ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
-			rc = -EINVAL;
+			rc = mdss_dsi_blank(pdata);
 		}
 		break;
-	case MDSS_EVENT_TIMEGEN_OFF:
+	case MDSS_EVENT_PANEL_OFF:
 		if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) {
-			pr_debug("%s:event=%d, calling unprepare: ctrl_state: %d\n",
-				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
-			rc = mdss_dsi_ctrl_unprepare(pdata);
+			rc = mdss_dsi_blank(pdata);
 		}
 		rc = mdss_dsi_off(pdata);
 		break;
@@ -665,6 +691,7 @@
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
 	}
+	pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc);
 	return rc;
 }
 
@@ -674,8 +701,6 @@
 	u32 index;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	pr_debug("%s\n", __func__);
-
 	if (pdev->dev.of_node) {
 		struct resource *mdss_dsi_mres;
 		const char *ctrl_name;
@@ -789,7 +814,7 @@
 struct device dsi_dev;
 
 int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode,
-			    unsigned char **ctrl_base)
+			struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int rc = 0;
 	u32 index;
@@ -828,21 +853,25 @@
 		return -ENOMEM;
 	}
 
-	*ctrl_base = ioremap(mdss_dsi_mres->start,
+	ctrl->ctrl_base = ioremap(mdss_dsi_mres->start,
 		resource_size(mdss_dsi_mres));
-	if (!(*ctrl_base)) {
+	if (!(ctrl->ctrl_base)) {
 		pr_err("%s:%d unable to remap dsi resources",
 			       __func__, __LINE__);
 		return -ENOMEM;
 	}
 
+	ctrl->reg_size = resource_size(mdss_dsi_mres);
+
+	pr_info("%s: dsi base=%x size=%x\n",
+		__func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+
 	return 0;
 }
 
 
 int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data,
-			      char backlight_ctrl)
+			      struct mdss_panel_common_pdata *panel_data)
 {
 	struct mipi_panel_info *mipi;
 	int rc;
@@ -851,7 +880,6 @@
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata;
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
-	unsigned char *ctrl_addr;
 	bool broadcast;
 	bool cont_splash_enabled = false;
 
@@ -891,8 +919,7 @@
 	else
 		bpp = 3;		/* Default format set to RGB888 */
 
-	if (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
-		!panel_data->panel_info.clk_rate) {
+	if (!panel_data->panel_info.clk_rate) {
 		h_period += panel_data->panel_info.lcdc.xres_pad;
 		v_period += panel_data->panel_info.lcdc.yres_pad;
 
@@ -961,6 +988,45 @@
 		}
 	}
 
+	ctrl_pdata->disp_te_gpio = of_get_named_gpio(pdev->dev.of_node,
+						     "qcom,te-gpio", 0);
+	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);
+			return -ENODEV;
+		}
+		pr_debug("%s: te_gpio=%d\n", __func__,
+					ctrl_pdata->disp_te_gpio);
+	}
+
+
 	ctrl_pdata->rst_gpio = of_get_named_gpio(pdev->dev.of_node,
 						 "qcom,rst-gpio", 0);
 	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -985,12 +1051,11 @@
 
 	if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev,
 					     panel_data->panel_info.pdest,
-					     &ctrl_addr)) {
+					     ctrl_pdata)) {
 		pr_err("%s: unable to get Dsi controller res\n", __func__);
 		return -EPERM;
 	}
 
-	pr_debug("%s: ctrl base address: 0x%x\n", __func__, (int)ctrl_addr);
 	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
 
 	ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds;
@@ -1001,9 +1066,16 @@
 				       sizeof(struct mdss_panel_info));
 
 	mdss_dsi_irq_handler_config(ctrl_pdata);
-	(ctrl_pdata->panel_data).set_backlight = panel_data->bl_fnc;
-	(ctrl_pdata->ctrl_base) = ctrl_addr;
-	(ctrl_pdata->bl_ctrl) = backlight_ctrl;
+	ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
+	ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
+	ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio;
+	ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
+	ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
+	ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
+
+	if (ctrl_pdata->bklt_ctrl == BL_PWM)
+		mdss_dsi_panel_pwm_cfg(ctrl_pdata);
+
 	/*
 	 * register in mdp driver
 	 */
@@ -1047,6 +1119,16 @@
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
 
+	if (panel_data->panel_info.pdest == DISPLAY_1) {
+		mdss_debug_register_base("dsi0",
+			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
+		ctrl_pdata->ndx = 0;
+	} else {
+		mdss_debug_register_base("dsi1",
+			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
+		ctrl_pdata->ndx = 1;
+	}
+
 	pr_debug("%s: Panal data initialized\n", __func__);
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index b365f36..197ff7a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -273,17 +273,27 @@
 };
 
 struct mdss_dsi_ctrl_pdata {
+	int ndx;
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
 	struct mdss_panel_data panel_data;
+	struct mdss_hw *mdss_hw;
 	unsigned char *ctrl_base;
-	char bl_ctrl;
+	int reg_size;
 	struct clk *byte_clk;
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
+	int irq_cnt;
 	int mdss_dsi_clk_on;
 	int rst_gpio;
 	int disp_en_gpio;
+	int disp_te_gpio;
+	int bklt_ctrl;	/* backlight ctrl */
+	int pwm_period;
+	int pwm_gpio;
+	int pwm_lpg_chan;
+	int bklt_max;
+	struct pwm_device *pwm_bl;
 	struct dsi_panel_cmds_list *on_cmds;
 	struct dsi_panel_cmds_list *off_cmds;
 	struct dsi_drv_cm_data shared_pdata;
@@ -293,8 +303,7 @@
 };
 
 int dsi_panel_device_register(struct platform_device *pdev,
-			      struct mdss_panel_common_pdata *panel_data,
-			      char bl_ctrl);
+			      struct mdss_panel_common_pdata *panel_data);
 
 char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mdss_dsi_buf_init(struct dsi_buf *dp);
@@ -343,5 +352,7 @@
 void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
 void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
 void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
+void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
+void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
 
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 6f7023c..ccec0fc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -26,7 +26,6 @@
 #include "mdss_dsi.h"
 
 static struct completion dsi_dma_comp;
-static int dsi_irq_enabled;
 static spinlock_t dsi_irq_lock;
 static spinlock_t dsi_mdp_lock;
 static int dsi_mdp_busy;
@@ -51,90 +50,47 @@
 	spin_lock_init(&dsi_mdp_lock);
 }
 
-void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1)
-		mdss_dsi0_hw.ptr = (void *)(ctrl_pdata);
-	else
-		mdss_dsi1_hw.ptr = (void *)(ctrl_pdata);
+	if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
+		mdss_dsi0_hw.ptr = (void *)(ctrl);
+		ctrl->mdss_hw = &mdss_dsi0_hw;
+	} else {
+		mdss_dsi1_hw.ptr = (void *)(ctrl);
+		ctrl->mdss_hw = &mdss_dsi1_hw;
+	}
 }
 
-void mdss_dsi_enable_irq(struct mdss_panel_data *pdata)
+void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
 {
 	unsigned long flags;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
+	if (ctrl == NULL) {
+		pr_err("%s: Invalid ctrl\n", __func__);
 		return;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
 	spin_lock_irqsave(&dsi_irq_lock, flags);
-	if (dsi_irq_enabled) {
-		pr_debug("%s: IRQ aleady enabled\n", __func__);
-		spin_unlock_irqrestore(&dsi_irq_lock, flags);
-		return;
+	if (enable) {
+		if (ctrl->irq_cnt == 0)
+			mdss_enable_irq(ctrl->mdss_hw);
+		ctrl->irq_cnt++;
+	} else {
+		if (ctrl->irq_cnt) {
+			ctrl->irq_cnt--;
+			if (ctrl->irq_cnt == 0) {
+				if (isr)
+					mdss_disable_irq_nosync(ctrl->mdss_hw);
+				else
+					mdss_disable_irq(ctrl->mdss_hw);
+			}
+		}
 	}
-
-	if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
-		mdss_enable_irq(&mdss_dsi0_hw);
-	else
-		mdss_enable_irq(&mdss_dsi1_hw);
-
-	dsi_irq_enabled = 1;
-	/* TO DO: Check whether MDSS IRQ is enabled */
+	pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__,
+					ctrl->ndx, enable, ctrl->irq_cnt);
 	spin_unlock_irqrestore(&dsi_irq_lock, flags);
 }
 
-void mdss_dsi_disable_irq(struct mdss_panel_data *pdata)
-{
-	unsigned long flags;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
-	spin_lock_irqsave(&dsi_irq_lock, flags);
-	if (dsi_irq_enabled == 0) {
-		pr_debug("%s: IRQ already disabled\n", __func__);
-		spin_unlock_irqrestore(&dsi_irq_lock, flags);
-		return;
-	}
-	if (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1)
-		mdss_disable_irq(&mdss_dsi0_hw);
-	else
-		mdss_disable_irq(&mdss_dsi1_hw);
-
-	dsi_irq_enabled = 0;
-	/* TO DO: Check whether MDSS IRQ is Disabled */
-	spin_unlock_irqrestore(&dsi_irq_lock, flags);
-}
-
-/*
- * mdss_dsi_disale_irq_nosync() should be called
- * from interrupt context
- */
-void mdss_dsi_disable_irq_nosync(void)
-{
-	spin_lock(&dsi_irq_lock);
-	if (dsi_irq_enabled == 0) {
-		pr_debug("%s: IRQ cannot be disabled\n", __func__);
-		spin_unlock(&dsi_irq_lock);
-		return;
-	}
-
-	dsi_irq_enabled = 0;
-	spin_unlock(&dsi_irq_lock);
-}
-
 /*
  * mipi dsi buf mechanism
  */
@@ -689,6 +645,30 @@
 	return len;
 }
 
+void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata)
+{
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	int i;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x201);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x016c, 0xff0000); /* red */
+	i = 0;
+	while (i++ < 50) {
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0184, 0x1);
+		/* Add sleep to get ~50 fps frame rate*/
+		msleep(20);
+	}
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x0);
+}
+
 void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
 				struct mdss_panel_data *pdata)
 {
@@ -745,7 +725,7 @@
 		if (pinfo->r_sel)
 			data |= BIT(4);
 		data |= (pinfo->dst_format & 0x0f);	/* 4 bits */
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x003c, data);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0040, data);
 
 		/* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */
 		data = pinfo->wr_mem_continue & 0x0ff;
@@ -830,6 +810,7 @@
 
 	dsi_ctrl |= BIT(0);	/* enable dsi */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0); /* enable dsi irq */
 
 	wmb();
 }
@@ -977,8 +958,6 @@
 				DSI_INTR_CMD_MDP_DONE_MASK;
 	}
 
-	pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl);
-
 	if (ctrl_pdata->shared_pdata.broadcast_enable)
 		if ((pdata->panel_info.pdest == DISPLAY_2)
 		  && (left_ctrl_pdata != NULL)) {
@@ -994,17 +973,6 @@
 	wmb();
 }
 
-void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata)
-{
-	unsigned long flag;
-
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_enable_irq(pdata);
-	dsi_mdp_busy = true;
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-}
-
-
 void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata)
 {
 	u32 status;
@@ -1116,7 +1084,7 @@
 	}
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_enable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
 
 	dsi_mdp_busy = true;
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
@@ -1134,7 +1102,7 @@
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
 	dsi_mdp_busy = false;
-	mdss_dsi_disable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
 	if (video_mode)
@@ -1206,7 +1174,7 @@
 	}
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_enable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
 	dsi_mdp_busy = true;
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
@@ -1243,7 +1211,7 @@
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
 	dsi_mdp_busy = false;
-	mdss_dsi_disable_irq(pdata);
+	mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 
 	if (pdata->panel_info.mipi.no_max_pkt_size) {
@@ -1288,7 +1256,6 @@
 			struct mdss_panel_data *pdata)
 {
 	int len;
-	int i;
 	int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
 	char *bp;
 	unsigned long size, addr;
@@ -1303,12 +1270,6 @@
 				panel_data);
 	bp = tp->data;
 
-	pr_debug("%s: ", __func__);
-	for (i = 0; i < tp->len; i++)
-		pr_debug("%x ", *bp++);
-
-	pr_debug("\n");
-
 	len = ALIGN(tp->len, 4);
 	size = ALIGN(tp->len, SZ_4K);
 
@@ -1495,6 +1456,8 @@
 			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
 		}
 
+	pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+
 	if (isr & DSI_INTR_ERROR)
 		mdss_dsi_error(dsi_base);
 
@@ -1510,7 +1473,6 @@
 	if (isr & DSI_INTR_CMD_MDP_DONE) {
 		spin_lock(&dsi_mdp_lock);
 		dsi_mdp_busy = false;
-		mdss_dsi_disable_irq_nosync();
 		spin_unlock(&dsi_mdp_lock);
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 8d38737..d24ed16 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -13,11 +13,14 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
-#include <linux/qpnp/pin.h>
+#include <linux/of_gpio.h>
 #include <linux/gpio.h>
+#include <linux/qpnp/pin.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
+#include <linux/pwm.h>
+#include <linux/err.h>
 
 #include "mdss_dsi.h"
 
@@ -30,6 +33,64 @@
 
 static struct mdss_dsi_phy_ctrl phy_params;
 
+void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	int ret;
+
+	if (!gpio_is_valid(ctrl->pwm_gpio)) {
+		pr_err("%s: pwm_gpio=%d Invalid\n", __func__,
+				ctrl->pwm_gpio);
+		return;
+	}
+
+	ret = gpio_request(ctrl->pwm_gpio, "disp_pwm");
+	if (ret) {
+		pr_err("%s: pwm_gpio=%d request failed\n", __func__,
+				ctrl->pwm_gpio);
+		return;
+	}
+
+	ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt");
+	if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
+		pr_err("%s: lpg_chan=%d pwm request failed", __func__,
+				ctrl->pwm_lpg_chan);
+		gpio_free(ctrl->pwm_gpio);
+		ctrl->pwm_gpio = -1;
+	}
+}
+
+static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level)
+{
+	int ret;
+	u32 duty;
+
+	if (ctrl->pwm_bl == NULL) {
+		pr_err("%s: no PWM\n", __func__);
+		return;
+	}
+
+	duty = level * ctrl->pwm_period;
+	duty /= ctrl->bklt_max;
+
+	pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n",
+			__func__, ctrl->bklt_ctrl, ctrl->pwm_period,
+				ctrl->pwm_gpio, ctrl->pwm_lpg_chan);
+
+	pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
+					ctrl->ndx, level, duty);
+
+	ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+	if (ret) {
+		pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+		return;
+	}
+
+	ret = pwm_enable(ctrl->pwm_bl);
+	if (ret)
+		pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
+}
+
+
 void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -84,46 +145,51 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	if (ctrl_pdata->bl_ctrl) {
-		switch (ctrl_pdata->bl_ctrl) {
-		case BL_WLED:
-			led_trigger_event(bl_led_trigger, bl_level);
-			break;
-
-		default:
-			pr_err("%s: Unknown bl_ctrl configuration\n",
-				__func__);
-			break;
-		}
-	} else
-		pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
+	switch (ctrl_pdata->bklt_ctrl) {
+	case BL_WLED:
+		led_trigger_event(bl_led_trigger, bl_level);
+		break;
+	case BL_PWM:
+		mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
+		break;
+	default:
+		pr_err("%s: Unknown bl_ctrl configuration\n",
+			__func__);
+		break;
+	}
 }
 
+static char set_tear_on[2] = {0x35, 0x00};
+static struct dsi_cmd_desc dsi_tear_on_cmd = {
+	DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on};
+
+static char set_tear_off[2] = {0x34, 0x00};
+static struct dsi_cmd_desc dsi_tear_off_cmd = {
+	DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off};
+
 static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
 {
 	struct mipi_panel_info *mipi;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return -EINVAL;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+	ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 	mipi  = &pdata->panel_info.mipi;
 
-	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
-		 mipi->mode);
+	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
 
-	if (mipi->mode == DSI_VIDEO_MODE) {
+	if (ctrl->on_cmds->size)
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-				 ctrl_pdata->on_cmds->buf,
-				 ctrl_pdata->on_cmds->size);
-	} else {
-		pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__);
-		return -EINVAL;
-	}
+				 ctrl->on_cmds->buf,
+				 ctrl->on_cmds->size);
+
+	mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
+			&dsi_tear_on_cmd, 1);
 
 	return 0;
 }
@@ -131,34 +197,33 @@
 static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
 {
 	struct mipi_panel_info *mipi;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return -EINVAL;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+	ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
+
+	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
+
 	mipi  = &pdata->panel_info.mipi;
 
-	pr_debug("%s:%d, debug info\n", __func__, __LINE__);
+	mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
+			&dsi_tear_off_cmd, 1);
 
-	if (mipi->mode == DSI_VIDEO_MODE) {
+	if (ctrl->off_cmds->size)
 		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-				 ctrl_pdata->off_cmds->buf,
-				 ctrl_pdata->off_cmds->size);
-	} else {
-		pr_debug("%s:%d, CMD mode not supported", __func__, __LINE__);
-		return -EINVAL;
-	}
+				 ctrl->off_cmds->buf,
+				 ctrl->off_cmds->size);
 
 	return 0;
 }
 
 static int mdss_panel_parse_dt(struct platform_device *pdev,
-			       struct mdss_panel_common_pdata *panel_data,
-			       char *bl_ctrl)
+			       struct mdss_panel_common_pdata *panel_data)
 {
 	struct device_node *np = pdev->dev.of_node;
 	u32 res[6], tmp;
@@ -229,7 +294,32 @@
 	if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) {
 		led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
 		pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
-		*bl_ctrl = BL_WLED;
+
+		panel_data->panel_info.bklt_ctrl = BL_WLED;
+	} else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
+		panel_data->panel_info.bklt_ctrl = BL_PWM;
+
+		rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp);
+		if (rc) {
+			pr_err("%s:%d, Error, dsi pwm_period\n",
+						__func__, __LINE__);
+			return -EINVAL;
+		}
+		panel_data->panel_info.pwm_period = tmp;
+
+		rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp);
+		if (rc) {
+			pr_err("%s:%d, Error, dsi lpg channel\n",
+						__func__, __LINE__);
+			return -EINVAL;
+		}
+		panel_data->panel_info.pwm_lpg_chan = tmp;
+
+		tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0);
+		panel_data->panel_info.pwm_gpio =  tmp;
+	} else {
+		pr_debug("%s: Unknown backlight control\n", __func__);
+		panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
 	}
 
 	rc = of_property_read_u32_array(np,
@@ -240,6 +330,13 @@
 	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
 	panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
 
+	rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp);
+	panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0);
+
+	rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp);
+	panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0);
+
+
 	rc = of_property_read_u32(np,
 		"qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
 	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
@@ -263,6 +360,26 @@
 			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
 
 	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-insert-dcs-cmd", &tmp);
+	panel_data->panel_info.mipi.insert_dcs_cmd =
+			(!rc ? tmp : 1);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-wr-mem-continue", &tmp);
+	panel_data->panel_info.mipi.wr_mem_continue =
+			(!rc ? tmp : 0x3c);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-wr-mem-start", &tmp);
+	panel_data->panel_info.mipi.wr_mem_start =
+			(!rc ? tmp : 0x2c);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-te-sel", &tmp);
+	panel_data->panel_info.mipi.te_sel =
+			(!rc ? tmp : 1);
+
+	rc = of_property_read_u32(np,
 		"qcom,mdss-pan-dsi-dst-format", &tmp);
 	panel_data->panel_info.mipi.dst_format =
 			(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
@@ -313,6 +430,9 @@
 	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
 	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
 
+	rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp);
+	panel_data->panel_info.clk_rate = (!rc ? tmp : 0);
+
 	data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
 	if ((!data) || (len != 7)) {
 		pr_err("%s:%d, Unable to read Phy regulator settings",
@@ -533,7 +653,6 @@
 	int rc = 0;
 	static struct mdss_panel_common_pdata vendor_pdata;
 	static const char *panel_name;
-	char bl_ctrl = UNKNOWN_CTRL;
 
 	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
 	if (!pdev->dev.of_node)
@@ -546,7 +665,7 @@
 	else
 		pr_info("%s: Panel Name = %s\n", __func__, panel_name);
 
-	rc = mdss_panel_parse_dt(pdev, &vendor_pdata, &bl_ctrl);
+	rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
 	if (rc)
 		return rc;
 
@@ -554,7 +673,7 @@
 	vendor_pdata.off = mdss_dsi_panel_off;
 	vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl;
 
-	rc = dsi_panel_device_register(pdev, &vendor_pdata, bl_ctrl);
+	rc = dsi_panel_device_register(pdev, &vendor_pdata);
 	if (rc)
 		return rc;
 
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 6986117..aea2de0 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -363,7 +363,7 @@
 	case MDSS_EVENT_UNBLANK:
 		rc = mdss_edp_on(pdata);
 		break;
-	case MDSS_EVENT_TIMEGEN_OFF:
+	case MDSS_EVENT_PANEL_OFF:
 		rc = mdss_edp_off(pdata);
 		break;
 	}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4e74858..ed730b3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -45,11 +45,8 @@
 
 #include <mach/board.h>
 #include <mach/memory.h>
-#include <mach/msm_memtypes.h>
-#include <mach/iommu_domains.h>
 
 #include "mdss_fb.h"
-#include "mdss_mdp.h"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MDSS_FB_NUM 3
@@ -68,6 +65,8 @@
 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
 };
 
+static struct msm_mdp_interface *mdp_instance;
+
 static int mdss_fb_register(struct msm_fb_data_type *mfd);
 static int mdss_fb_open(struct fb_info *info, int user);
 static int mdss_fb_release(struct fb_info *info, int user);
@@ -261,6 +260,7 @@
 	mfd->pdev = pdev;
 	if (pdata->next)
 		mfd->split_display = true;
+	mfd->mdp = *mdp_instance;
 
 	mutex_init(&mfd->lock);
 
@@ -272,6 +272,14 @@
 	if (rc)
 		return rc;
 
+	if (mfd->mdp.init_fnc) {
+		rc = mfd->mdp.init_fnc(mfd);
+		if (rc) {
+			pr_err("init_fnc failed\n");
+			return rc;
+		}
+	}
+
 	rc = pm_runtime_set_active(mfd->fbi->dev);
 	if (rc < 0)
 		pr_err("pm_runtime: fail to set active.\n");
@@ -301,11 +309,7 @@
 		}
 	}
 
-	rc = mdss_mdp_overlay_init(mfd);
-	if (rc)
-		pr_err("unable to init overlay\n");
-
-	return 0;
+	return rc;
 }
 
 static int mdss_fb_remove(struct platform_device *pdev)
@@ -503,24 +507,6 @@
 static int unset_bl_level, bl_updated;
 static int bl_level_old;
 
-static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
-						struct mdp_bl_scale_data *data)
-{
-	int ret = 0;
-	int curr_bl;
-	mutex_lock(&mfd->lock);
-	curr_bl = mfd->bl_level;
-	mfd->bl_scale = data->scale;
-	mfd->bl_min_lvl = data->min_lvl;
-	pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
-							mfd->bl_min_lvl);
-
-	/* update current backlight to use new scaling*/
-	mdss_fb_set_backlight(mfd, curr_bl);
-	mutex_unlock(&mfd->lock);
-	return ret;
-}
-
 static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
 {
 	u32 temp = *bl_lvl;
@@ -601,9 +587,8 @@
 
 	switch (blank_mode) {
 	case FB_BLANK_UNBLANK:
-		if (!mfd->panel_power_on) {
-			msleep(20);
-			ret = mfd->on_fnc(mfd);
+		if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
+			ret = mfd->mdp.on_fnc(mfd);
 			if (ret == 0)
 				mfd->panel_power_on = true;
 		}
@@ -614,7 +599,7 @@
 	case FB_BLANK_NORMAL:
 	case FB_BLANK_POWERDOWN:
 	default:
-		if (mfd->panel_power_on) {
+		if (mfd->panel_power_on && mfd->mdp.off_fnc) {
 			int curr_pwr_state;
 
 			del_timer(&mfd->no_update.timer);
@@ -625,8 +610,7 @@
 			mfd->panel_power_on = false;
 			bl_updated = 0;
 
-			msleep(20);
-			ret = mfd->off_fnc(mfd);
+			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
 				mfd->panel_power_on = curr_pwr_state;
 			else
@@ -731,28 +715,11 @@
 
 static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
 {
-	void *virt = NULL;
-	unsigned long phys = 0;
-	size_t size;
-	u32 yres = mfd->fbi->var.yres_virtual;
-
-	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
-	if (mfd->index == 0) {
-		if (mdss_mdp_alloc_fb_mem(mfd, size, (u32 *)&phys, &virt))
-			return  -ENOMEM;
-		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
-			size, virt, phys, mfd->index);
-	} else {
-		pr_debug("no memory allocated for fb%d\n", mfd->index);
-		size = 0;
+	if (!mfd->mdp.fb_mem_alloc_fnc) {
+		pr_err("no fb memory allocator function defined\n");
+		return -ENOMEM;
 	}
-
-	mfd->fbi->screen_base = virt;
-	mfd->fbi->fix.smem_start = phys;
-	mfd->fbi->fix.smem_len = size;
-
-	return 0;
+	return mfd->mdp.fb_mem_alloc_fnc(mfd);
 }
 
 static int mdss_fb_register(struct msm_fb_data_type *mfd)
@@ -899,7 +866,11 @@
 		var->xres *= 2;
 
 	fix->type = panel_info->is_3d_panel;
-	fix->line_length = mdss_mdp_fb_stride(mfd->index, var->xres, bpp);
+	if (mfd->mdp.fb_stride)
+		fix->line_length = mfd->mdp.fb_stride(mfd->index, var->xres,
+							bpp);
+	else
+		fix->line_length = var->xres * bpp;
 
 	var->yres = panel_info->yres;
 	var->xres_virtual = var->xres;
@@ -949,15 +920,13 @@
 		pr_err("error: not enough memory!\n");
 		return -ENOMEM;
 	}
-	if (mfd->lut_update) {
-		ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-		if (ret)
-			pr_err("fb_alloc_cmap() failed!\n");
-	}
+
+	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+	if (ret)
+		pr_err("fb_alloc_cmap() failed!\n");
 
 	if (register_framebuffer(fbi) < 0) {
-		if (mfd->lut_update)
-			fb_dealloc_cmap(&fbi->cmap);
+		fb_dealloc_cmap(&fbi->cmap);
 
 		mfd->op_enable = false;
 		return -EPERM;
@@ -1200,8 +1169,8 @@
 		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
 
 	mdss_fb_wait_for_fence(mfd);
-	if (mfd->dma_fnc)
-		mfd->dma_fnc(mfd);
+	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);
@@ -1238,7 +1207,8 @@
 	if (fb_backup->disp_commit.flags &
 		MDP_DISPLAY_COMMIT_OVERLAY) {
 		mdss_fb_wait_for_fence(mfd);
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+		if (mfd->mdp.kickoff_fnc)
+			mfd->mdp.kickoff_fnc(mfd);
 		mdss_fb_signal_timeline(mfd);
 	} else {
 		var = &fb_backup->disp_commit.var;
@@ -1403,8 +1373,14 @@
 		return -EINVAL;
 	}
 
-	mfd->fbi->fix.line_length = mdss_mdp_fb_stride(mfd->index, var->xres,
+
+	if (mfd->mdp.fb_stride)
+		mfd->fbi->fix.line_length = mfd->mdp.fb_stride(mfd->index,
+						var->xres,
 						var->bits_per_pixel / 8);
+	else
+		mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+
 
 	if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
 		mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
@@ -1422,14 +1398,14 @@
 	struct fb_cursor cursor;
 	int ret;
 
-	if (!mfd->cursor_update)
+	if (!mfd->mdp.cursor_update)
 		return -ENODEV;
 
 	ret = copy_from_user(&cursor, p, sizeof(cursor));
 	if (ret)
 		return ret;
 
-	return mfd->cursor_update(mfd, &cursor);
+	return mfd->mdp.cursor_update(mfd, &cursor);
 }
 
 static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
@@ -1438,86 +1414,17 @@
 	struct fb_cmap cmap;
 	int ret;
 
-	if (!mfd->lut_update)
+	if (!mfd->mdp.lut_update)
 		return -ENODEV;
 
 	ret = copy_from_user(&cmap, p, sizeof(cmap));
 	if (ret)
 		return ret;
 
-	mfd->lut_update(mfd, &cmap);
+	mfd->mdp.lut_update(mfd, &cmap);
 	return 0;
 }
 
-static int mdss_fb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
-							void __user *argp)
-{
-	int ret;
-	struct msmfb_mdp_pp mdp_pp;
-	u32 copyback = 0;
-
-	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
-	if (ret)
-		return ret;
-
-	switch (mdp_pp.op) {
-	case mdp_op_pa_cfg:
-		ret = mdss_mdp_pa_config(mfd->ctl, &mdp_pp.data.pa_cfg_data,
-				&copyback);
-		break;
-
-	case mdp_op_pcc_cfg:
-		ret = mdss_mdp_pcc_config(mfd->ctl, &mdp_pp.data.pcc_cfg_data,
-			   &copyback);
-		break;
-
-	case mdp_op_lut_cfg:
-		switch (mdp_pp.data.lut_cfg_data.lut_type) {
-		case mdp_lut_igc:
-			ret = mdss_mdp_igc_lut_config(mfd->ctl,
-					(struct mdp_igc_lut_data *)
-					&mdp_pp.data.lut_cfg_data.data,
-					&copyback);
-			break;
-
-		case mdp_lut_pgc:
-			ret = mdss_mdp_argc_config(mfd->ctl,
-				&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
-				&copyback);
-			break;
-
-		case mdp_lut_hist:
-			ret = mdss_mdp_hist_lut_config(mfd->ctl,
-				(struct mdp_hist_lut_data *)
-				&mdp_pp.data.lut_cfg_data.data, &copyback);
-			break;
-
-		default:
-			ret = -ENOTSUPP;
-			break;
-		}
-		break;
-	case mdp_op_dither_cfg:
-		ret = mdss_mdp_dither_config(mfd->ctl,
-				&mdp_pp.data.dither_cfg_data, &copyback);
-		break;
-	case mdp_op_gamut_cfg:
-		ret = mdss_mdp_gamut_config(mfd->ctl,
-					&mdp_pp.data.gamut_cfg_data, &copyback);
-		break;
-	case mdp_bl_scale_cfg:
-		ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
-						&mdp_pp.data.bl_scale_data);
-		break;
-	default:
-		pr_err("Unsupported request to MDP_PP IOCTL.\n");
-		ret = -EINVAL;
-		break;
-	}
-	if ((ret == 0) && copyback)
-		ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
-	return ret;
-}
 static int mdss_fb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
 						struct mdp_buf_sync *buf_sync)
 {
@@ -1618,74 +1525,15 @@
 	return ret;
 }
 
-static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
-				struct msmfb_metadata *metadata)
-{
-	int ret = 0;
-	switch (metadata->op) {
-	case metadata_op_vic:
-		if (mfd->panel_info)
-			mfd->panel_info->vic =
-				metadata->data.video_info_code;
-		else
-			ret = -EINVAL;
-		break;
-	default:
-		pr_warn("unsupported request to MDP META IOCTL\n");
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-
-static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
-		struct mdss_hw_caps *caps)
-{
-	struct mdss_data_type *mdata = mfd->mdata;
-
-	if (!mdata)
-		return -ENODEV;
-
-	caps->mdp_rev = mdata->mdp_rev;
-	caps->vig_pipes = mdata->nvig_pipes;
-	caps->rgb_pipes = mdata->nrgb_pipes;
-	caps->dma_pipes = mdata->ndma_pipes;
-
-	return 0;
-}
-
-static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
-				struct msmfb_metadata *metadata)
-{
-	int ret = 0;
-	switch (metadata->op) {
-	case metadata_op_frame_rate:
-		metadata->data.panel_frame_rate =
-			mdss_get_panel_framerate(mfd);
-		break;
-	case metadata_op_get_caps:
-		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
-		break;
-	default:
-		pr_warn("Unsupported request to MDP META IOCTL.\n");
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
 
 static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			 unsigned long arg)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	void __user *argp = (void __user *)arg;
-	struct mdp_histogram_data hist;
-	struct mdp_histogram_start_req hist_req;
-	u32 block, hist_data_addr = 0;
 	struct mdp_page_protection fb_page_protection;
 	int ret = -ENOSYS;
 	struct mdp_buf_sync buf_sync;
-	struct msmfb_metadata metadata;
 
 	mdss_fb_power_setting_idle(mfd);
 
@@ -1700,43 +1548,6 @@
 		ret = mdss_fb_set_lut(info, argp);
 		break;
 
-	case MSMFB_HISTOGRAM:
-		if (!mfd->panel_power_on)
-			return -EPERM;
-
-		ret = copy_from_user(&hist, argp, sizeof(hist));
-		if (ret)
-			return ret;
-
-		ret = mdss_mdp_hist_collect(mfd->ctl, &hist, &hist_data_addr);
-		if ((ret == 0) && hist_data_addr) {
-			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
-				sizeof(u32) * hist.bin_cnt);
-			if (ret == 0)
-				ret = copy_to_user(argp, &hist,
-						   sizeof(hist));
-		}
-		break;
-
-	case MSMFB_HISTOGRAM_START:
-		if (!mfd->panel_power_on)
-			return -EPERM;
-
-		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
-		if (ret)
-			return ret;
-
-		ret = mdss_mdp_histogram_start(mfd->ctl, &hist_req);
-		break;
-
-	case MSMFB_HISTOGRAM_STOP:
-		ret = copy_from_user(&block, argp, sizeof(int));
-		if (ret)
-			return ret;
-
-		ret = mdss_mdp_histogram_stop(mfd->ctl, block);
-		break;
-
 	case MSMFB_GET_PAGE_PROTECTION:
 		fb_page_protection.page_protection =
 			mfd->mdp_fb_page_protection;
@@ -1746,10 +1557,6 @@
 			return ret;
 		break;
 
-	case MSMFB_MDP_PP:
-		ret = mdss_fb_handle_pp_ioctl(mfd, argp);
-		break;
-
 	case MSMFB_BUFFER_SYNC:
 		ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
 		if (ret)
@@ -1769,25 +1576,9 @@
 		ret = mdss_fb_display_commit(info, argp);
 		break;
 
-	case MSMFB_METADATA_SET:
-		ret = copy_from_user(&metadata, argp, sizeof(metadata));
-		if (ret)
-			return ret;
-		ret = mdss_fb_set_metadata(mfd, &metadata);
-		break;
-
-	case MSMFB_METADATA_GET:
-		ret = copy_from_user(&metadata, argp, sizeof(metadata));
-		if (ret)
-			return ret;
-		ret = mdss_fb_get_metadata(mfd, &metadata);
-		if (!ret)
-			ret = copy_to_user(argp, &metadata, sizeof(metadata));
-		break;
-
 	default:
-		if (mfd->ioctl_handler)
-			ret = mfd->ioctl_handler(mfd, cmd, argp);
+		if (mfd->mdp.ioctl_handler)
+			ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
 		break;
 	}
 
@@ -1853,6 +1644,11 @@
 		return -ENODEV;
 	}
 
+	if (!mdp_instance) {
+		pr_err("mdss mdp resource not initialized yet\n");
+		return -ENODEV;
+	}
+
 	node = of_parse_phandle(pdev->dev.of_node, "qcom,mdss-fb-map", 0);
 	if (!node) {
 		pr_err("Unable to find fb node for device: %s\n",
@@ -1876,23 +1672,27 @@
 		fb_pdev->dev.platform_data = pdata;
 	}
 
-	/*
-	 * Clocks are already on if continuous splash is enabled,
-	 * increasing ref_cnt to help balance clocks once done.
-	 */
-	if (pdata->panel_info.cont_splash_enabled) {
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		mdss_mdp_footswitch_ctrl_splash(1);
-		mdss_mdp_copy_splash_screen(pdata);
-	}
+	if (mdp_instance->panel_register_done)
+		mdp_instance->panel_register_done(pdata);
 
 mdss_notfound:
 	of_node_put(node);
-
 	return rc;
 }
 EXPORT_SYMBOL(mdss_register_panel);
 
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp)
+{
+	if (mdp_instance) {
+		pr_err("multiple MDP instance registration");
+		return -EINVAL;
+	}
+
+	mdp_instance = mdp;
+	return 0;
+}
+EXPORT_SYMBOL(mdss_fb_register_mdp_instance);
+
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
 {
 	struct fb_info *info;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index db2e305..fdbbea9 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -19,7 +19,6 @@
 #include <linux/msm_mdp.h>
 #include <linux/types.h>
 
-#include "mdss_mdp.h"
 #include "mdss_panel.h"
 
 #define MSM_FB_DEFAULT_PAGE_SIZE 2
@@ -53,6 +52,26 @@
 	struct mutex lock;
 };
 
+struct msm_fb_data_type;
+
+struct msm_mdp_interface {
+	int (*fb_mem_alloc_fnc)(struct msm_fb_data_type *mfd);
+	int (*init_fnc)(struct msm_fb_data_type *mfd);
+	int (*on_fnc)(struct msm_fb_data_type *mfd);
+	int (*off_fnc)(struct msm_fb_data_type *mfd);
+	int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
+	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,
+				struct fb_cursor *cursor);
+	int (*lut_update)(struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
+	int (*do_histogram)(struct msm_fb_data_type *mfd,
+				struct mdp_histogram *hist);
+	int (*panel_register_done)(struct mdss_panel_data *pdata);
+	u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+	void *private1;
+};
+
 struct msm_fb_data_type {
 	u32 key;
 	u32 index;
@@ -71,30 +90,9 @@
 	int panel_reconfig;
 
 	u32 dst_format;
-	int vsync_pending;
-	ktime_t vsync_time;
-	struct completion vsync_comp;
-	spinlock_t vsync_lock;
-	int borderfill_enable;
-
-	int hw_refresh;
-
-	int overlay_play_enable;
-
 	int panel_power_on;
 	struct disp_info_type_suspend suspend;
 
-	int (*on_fnc) (struct msm_fb_data_type *mfd);
-	int (*off_fnc) (struct msm_fb_data_type *mfd);
-	int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
-	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,
-			      struct fb_cursor *cursor);
-	int (*lut_update) (struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
-	int (*do_histogram) (struct msm_fb_data_type *mfd,
-			     struct mdp_histogram *hist);
-
 	struct ion_handle *ihdl;
 	unsigned long iova;
 	void *cursor_buf;
@@ -105,21 +103,16 @@
 	u32 bl_scale;
 	u32 bl_min_lvl;
 	struct mutex lock;
-	struct mutex ov_lock;
 
 	struct platform_device *pdev;
 
 	u32 mdp_fb_page_protection;
 
-	struct mdss_data_type *mdata;
-	struct mdss_mdp_ctl *ctl;
-	struct mdss_mdp_wb *wb;
-	struct list_head overlay_list;
-	struct list_head pipes_used;
-	struct list_head pipes_cleanup;
 	struct disp_info_notify update;
 	struct disp_info_notify no_update;
 
+	struct msm_mdp_interface mdp;
+
 	u32 acq_fen_cnt;
 	struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
 	int cur_rel_fen_fd;
@@ -150,5 +143,5 @@
 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);
-
+int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index b93efd9..6a96369 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2539,7 +2539,7 @@
 				__func__, rc);
 		break;
 
-	case MDSS_EVENT_TIMEGEN_ON:
+	case MDSS_EVENT_PANEL_ON:
 		if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
 			DEV_DBG("%s: Starting HDCP authentication\n", __func__);
 			rc = hdmi_hdcp_authenticate(
@@ -2575,7 +2575,7 @@
 		}
 		break;
 
-	case MDSS_EVENT_TIMEGEN_OFF:
+	case MDSS_EVENT_PANEL_OFF:
 		hdmi_ctrl->timing_gen_on = false;
 		break;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 217ac18..e89fc7a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -55,6 +55,12 @@
 #include "mdss_debug.h"
 
 struct mdss_data_type *mdss_res;
+struct msm_mdp_interface mdp5 = {
+	.init_fnc = mdss_mdp_overlay_init,
+	.fb_mem_alloc_fnc = mdss_mdp_alloc_fb_mem,
+	.panel_register_done = mdss_panel_register_done,
+	.fb_stride = mdss_mdp_fb_stride,
+};
 
 #define IB_QUOTA 800000000
 #define AB_QUOTA 800000000
@@ -129,23 +135,36 @@
 static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
 
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
-			  u32 size, u32 *phys, void **virt)
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd)
 {
 	int dom;
-	void *fb_virt;
-	u32 fb_phys;
-	fb_virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
-	if (!fb_virt) {
-		pr_err("unable to alloc fbmem size=%u\n", size);
-		return -ENOMEM;
-	}
-	fb_phys = memory_pool_node_paddr(fb_virt);
-	dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
-	msm_iommu_map_contig_buffer(fb_phys, dom, 0, size, SZ_4K,
-					0, &(mfd->iova));
-	*phys = fb_phys;
-	*virt = fb_virt;
+	void *virt = NULL;
+	unsigned long phys = 0;
+	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
+	if (mfd->index == 0) {
+		virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+		if (!virt) {
+			pr_err("unable to alloc fbmem size=%u\n", size);
+			return -ENOMEM;
+		}
+		phys = memory_pool_node_paddr(virt);
+		dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+		msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+					&mfd->iova);
+
+		pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
+			size, virt, phys, mfd->index);
+	} else
+		size = 0;
+
+	mfd->fbi->screen_base = virt;
+	mfd->fbi->fix.smem_start = phys;
+	mfd->fbi->fix.smem_len = size;
+
 	return 0;
 }
 
@@ -994,6 +1013,10 @@
 	if (!pm_runtime_enabled(&pdev->dev))
 		mdss_mdp_footswitch_ctrl(mdata, true);
 
+	rc = mdss_fb_register_mdp_instance(&mdp5);
+	if (rc)
+		pr_err("unable to register mdp instance\n");
+
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_res = NULL;
@@ -1212,9 +1235,10 @@
 static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev)
 {
 
-	u32 nmixers, ndspp;
+	u32 nmixers, ndspp, npingpong;
 	int rc = 0;
-	u32 *mixer_offsets = NULL, *dspp_offsets = NULL;
+	u32 *mixer_offsets = NULL, *dspp_offsets = NULL,
+	    *pingpong_offsets = NULL;
 
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
 
@@ -1224,6 +1248,8 @@
 				"qcom,mdss-mixer-wb-off");
 	ndspp = mdss_mdp_parse_dt_prop_len(pdev,
 				"qcom,mdss-dspp-off");
+	npingpong = mdss_mdp_parse_dt_prop_len(pdev,
+				"qcom,mdss-pingpong-off");
 	nmixers = mdata->nmixers_intf + mdata->nmixers_wb;
 
 	if (mdata->nmixers_intf != ndspp) {
@@ -1231,6 +1257,11 @@
 		return -EINVAL;
 	}
 
+	if (mdata->nmixers_intf != npingpong) {
+		pr_err("device tree err: unequal no of pingpong and intf mixers\n");
+		return -EINVAL;
+	}
+
 	mixer_offsets = kzalloc(sizeof(u32) * nmixers, GFP_KERNEL);
 	if (!mixer_offsets) {
 		pr_err("no mem assigned: kzalloc fail\n");
@@ -1243,6 +1274,12 @@
 		rc = -ENOMEM;
 		goto dspp_alloc_fail;
 	}
+	pingpong_offsets = kzalloc(sizeof(u32) * npingpong, GFP_KERNEL);
+	if (!pingpong_offsets) {
+		pr_err("no mem assigned: kzalloc fail\n");
+		rc = -ENOMEM;
+		goto pingpong_alloc_fail;
+	}
 
 	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-mixer-intf-off",
 		mixer_offsets, mdata->nmixers_intf);
@@ -1259,19 +1296,26 @@
 	if (rc)
 		goto parse_done;
 
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pingpong-off",
+		pingpong_offsets, npingpong);
+	if (rc)
+		goto parse_done;
+
 	rc = mdss_mdp_mixer_addr_setup(mdata, mixer_offsets,
-			dspp_offsets, MDSS_MDP_MIXER_TYPE_INTF,
-			mdata->nmixers_intf);
+			dspp_offsets, pingpong_offsets,
+			MDSS_MDP_MIXER_TYPE_INTF, mdata->nmixers_intf);
 	if (rc)
 		goto parse_done;
 
 	rc = mdss_mdp_mixer_addr_setup(mdata, mixer_offsets +
-			mdata->nmixers_intf, NULL,
+			mdata->nmixers_intf, NULL, NULL,
 			MDSS_MDP_MIXER_TYPE_WRITEBACK, mdata->nmixers_wb);
 	if (rc)
 		goto parse_done;
 
 parse_done:
+	kfree(pingpong_offsets);
+pingpong_alloc_fail:
 	kfree(dspp_offsets);
 dspp_alloc_fail:
 	kfree(mixer_offsets);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 14c1e52..38e5436 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -156,6 +156,7 @@
 	u32 ref_cnt;
 	char __iomem *base;
 	char __iomem *dspp_base;
+	char __iomem *pingpong_base;
 	u8 type;
 	u8 params_changed;
 	u16 width;
@@ -283,6 +284,24 @@
 	void *priv_data;
 };
 
+struct mdss_overlay_private {
+	int vsync_pending;
+	ktime_t vsync_time;
+	struct completion vsync_comp;
+	spinlock_t vsync_lock;
+	int borderfill_enable;
+	int overlay_play_enable;
+	int hw_refresh;
+
+	struct mdss_data_type *mdata;
+	struct mutex ov_lock;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_wb *wb;
+	struct list_head overlay_list;
+	struct list_head pipes_used;
+	struct list_head pipes_cleanup;
+};
+
 #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)
@@ -295,6 +314,17 @@
 	return readl_relaxed(ctl->base + reg);
 }
 
+static inline void mdss_mdp_pingpong_write(struct mdss_mdp_mixer *mixer,
+				      u32 reg, u32 val)
+{
+	writel_relaxed(val, mixer->pingpong_base + reg);
+}
+
+static inline u32 mdss_mdp_pingpong_read(struct mdss_mdp_mixer *mixer, u32 reg)
+{
+	return readl_relaxed(mixer->pingpong_base + reg);
+}
+
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
 int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
@@ -319,11 +349,12 @@
 int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
 		u32 *offsets,  u32 count);
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
+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 mdss_mdp_ctl *ctl);
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd);
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
-				       struct msm_fb_data_type *mfd);
+					struct msm_fb_data_type *mfd);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
@@ -400,7 +431,7 @@
 int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
 		u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
 int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
-		u32 *dspp_offsets, u32 type, u32 len);
+		u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
 int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
 		u32 *wb_offsets, u32 len);
 
@@ -417,11 +448,21 @@
 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_wb_kickoff(struct mdss_mdp_ctl *ctl);
+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);
 
 int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
-				  u32 size, u32 *phys, void **virt);
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd);
 u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
+
+int mdss_panel_register_done(struct mdss_panel_data *pdata);
+
+#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
+#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
+				(mfd->mdp.private1))->mdata)
+#define mfd_to_ctl(mfd) (((struct mdss_overlay_private *)\
+				(mfd->mdp.private1))->ctl)
+#define mfd_to_wb(mfd) (((struct mdss_overlay_private *)\
+				(mfd->mdp.private1))->wb)
+
 #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 e850321..108340d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -575,7 +575,8 @@
 	struct mdss_mdp_ctl *ctl;
 	int ret = 0;
 
-	ctl = mdss_mdp_ctl_alloc(mfd->mdata);
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	ctl = mdss_mdp_ctl_alloc(mdata);
 	if (!ctl) {
 		pr_err("unable to allocate ctl\n");
 		return ERR_PTR(-ENOMEM);
@@ -599,6 +600,15 @@
 		ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
 		ctl->start_fnc = mdss_mdp_video_start;
 		break;
+	case MIPI_CMD_PANEL:
+		if (pdata->panel_info.pdest == DISPLAY_1)
+			ctl->intf_num = MDSS_MDP_INTF1;
+		else
+			ctl->intf_num = MDSS_MDP_INTF2;
+		ctl->intf_type = MDSS_INTF_DSI;
+		ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE;
+		ctl->start_fnc = mdss_mdp_cmd_start;
+		break;
 	case DTV_PANEL:
 		ctl->intf_num = MDSS_MDP_INTF3;
 		ctl->intf_type = MDSS_INTF_HDMI;
@@ -1032,7 +1042,8 @@
 }
 
 int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata,
-	 u32 *mixer_offsets, u32 *dspp_offsets, u32 type, u32 len)
+	 u32 *mixer_offsets, u32 *dspp_offsets, u32 *pingpong_offsets,
+	 u32 type, u32 len)
 {
 	struct mdss_mdp_mixer *head;
 	u32 i;
@@ -1052,8 +1063,11 @@
 		head[i].base = mdata->mdp_base + mixer_offsets[i];
 		head[i].ref_cnt = 0;
 		head[i].num = i;
-		if (type == MDSS_MDP_MIXER_TYPE_INTF)
+		if (type == MDSS_MDP_MIXER_TYPE_INTF) {
 			head[i].dspp_base = mdata->mdp_base + dspp_offsets[i];
+			head[i].pingpong_base = mdata->mdp_base +
+				pingpong_offsets[i];
+		}
 	}
 
 	switch (type) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 18c38a0..bf78c61 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -431,8 +431,6 @@
 	MDSS_MDP_MAX_PINGPONG
 };
 
-#define MDSS_MDP_REG_PP_OFFSET(pp)	(0x21B00 + ((pp) * 0x100))
-
 #define MDSS_MDP_REG_PP_TEAR_CHECK_EN			0x000
 #define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC		0x004
 #define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT		0x008
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
new file mode 100644
index 0000000..d6b0fb2
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -0,0 +1,333 @@
+/* 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 "mdss_panel.h"
+#include "mdss_mdp.h"
+
+#define START_THRESHOLD 4
+#define CONTINUE_TRESHOLD 4
+
+#define MAX_SESSIONS 2
+
+struct mdss_mdp_cmd_ctx {
+	u32 pp_num;
+	u8 ref_cnt;
+
+	struct completion pp_comp;
+	atomic_t vsync_ref;
+	spinlock_t vsync_lock;
+	mdp_vsync_handler_t vsync_handler;
+	int panel_on;
+
+	/* te config */
+	u8 tear_check;
+	u16 total_lcd_lines;
+	u16 v_porch;	/* vertical porches */
+	u32 vsync_cnt;
+};
+
+struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
+
+static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
+			struct mdss_mdp_cmd_ctx *ctx, int enable)
+{
+	u32 cfg;
+
+	cfg = BIT(19); /* VSYNC_COUNTER_EN */
+	if (ctx->tear_check)
+		cfg |= BIT(20);	/* VSYNC_IN_EN */
+	cfg |= ctx->vsync_cnt;
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
+				0xfff0); /* set to verh height */
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL, 0);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ, 0);
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS, ctx->v_porch);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
+			   (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
+	return 0;
+}
+
+static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, int enable)
+{
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	struct mdss_panel_info *pinfo;
+	struct mdss_mdp_mixer *mixer;
+
+	pinfo = &ctl->panel_data->panel_info;
+
+	if (pinfo->mipi.vsync_enable && enable) {
+		u32 mdp_vsync_clk_speed_hz, total_lines;
+		u32 vsync_cnt_cfg_dem;
+
+		mdss_mdp_vsync_clk_enable(1);
+
+		mdp_vsync_clk_speed_hz =
+		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
+		pr_debug("%s: vsync_clk_rate=%d\n", __func__,
+					mdp_vsync_clk_speed_hz);
+
+		if (mdp_vsync_clk_speed_hz == 0) {
+			pr_err("can't get clk speed\n");
+			return -EINVAL;
+		}
+
+		ctx->tear_check = pinfo->mipi.hw_vsync_mode;
+
+		total_lines = pinfo->lcdc.v_back_porch +
+				    pinfo->lcdc.v_front_porch +
+				    pinfo->lcdc.v_pulse_width + pinfo->yres;
+
+		vsync_cnt_cfg_dem =
+			mult_frac(pinfo->mipi.frame_rate * total_lines,
+						1, 100);
+
+		ctx->vsync_cnt = mdp_vsync_clk_speed_hz / vsync_cnt_cfg_dem;
+
+		ctx->v_porch = pinfo->lcdc.v_back_porch +
+				    pinfo->lcdc.v_front_porch +
+				    pinfo->lcdc.v_pulse_width;
+		ctx->total_lcd_lines = total_lines;
+	} else {
+		enable = 0;
+	}
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (mixer)
+		mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+	if (mixer)
+		mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
+
+	return 0;
+}
+
+static inline void cmd_readptr_irq_enable(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+	if (atomic_inc_return(&ctx->vsync_ref) == 1) {
+		pr_debug("%s:\n", __func__);
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+	}
+}
+
+static inline void cmd_readptr_irq_disable(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+	if (atomic_dec_return(&ctx->vsync_ref) == 0) {
+		pr_debug("%s:\n", __func__);
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+							ctx->pp_num);
+	}
+}
+
+int mdss_mdp_cmd_set_vsync_handler(struct mdss_mdp_ctl *ctl,
+		mdp_vsync_handler_t vsync_handler)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	unsigned long flags;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&ctx->vsync_lock, flags);
+
+	if (!ctx->vsync_handler && vsync_handler) {
+		ctx->vsync_handler = vsync_handler;
+		cmd_readptr_irq_enable(ctl);
+	} else if (ctx->vsync_handler && !vsync_handler) {
+		cmd_readptr_irq_disable(ctl);
+		ctx->vsync_handler = vsync_handler;
+	}
+
+	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+
+	return 0;
+}
+
+static void mdss_mdp_cmd_readptr_done(void *arg)
+{
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	ktime_t vsync_time;
+
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return;
+	}
+
+	pr_debug("%s: ctl=%d intf_num=%d\n", __func__, ctl->num, ctl->intf_num);
+
+	vsync_time = ktime_get();
+
+	spin_lock(&ctx->vsync_lock);
+	if (ctx->vsync_handler)
+		ctx->vsync_handler(ctl, vsync_time);
+	spin_unlock(&ctx->vsync_lock);
+}
+
+static void mdss_mdp_cmd_pingpong_done(void *arg)
+{
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+
+	pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
+
+	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
+
+	if (ctx)
+		complete(&ctx->pp_comp);
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	int rc;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
+					ctl->intf_num, ctx);
+
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	if (ctx->panel_on == 0) {
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
+		WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+
+		ctx->panel_on++;
+
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
+		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
+	}
+
+	INIT_COMPLETION(ctx->pp_comp);
+	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
+
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+
+	wait_for_completion_interruptible(&ctx->pp_comp);
+
+	return 0;
+}
+
+int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	int ret;
+
+	pr_debug("%s: +\n", __func__);
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	ctx->panel_on = 0;
+
+	mdss_mdp_cmd_set_vsync_handler(ctl, NULL);
+
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
+				   NULL, NULL);
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   NULL, NULL);
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctl->priv_data = NULL;
+
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
+	WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
+	WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	pr_debug("%s:-\n", __func__);
+
+	return 0;
+}
+
+int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	struct mdss_mdp_mixer *mixer;
+	int i, ret;
+
+	pr_debug("%s:+\n", __func__);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (!mixer) {
+		pr_err("mixer not setup correctly\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < MAX_SESSIONS; i++) {
+		ctx = &mdss_mdp_cmd_ctx_list[i];
+		if (ctx->ref_cnt == 0) {
+			ctx->ref_cnt++;
+			break;
+		}
+	}
+	if (i == MAX_SESSIONS) {
+		pr_err("too many sessions\n");
+		return -ENOMEM;
+	}
+
+	ctl->priv_data = ctx;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	ctx->pp_num = mixer->num;
+	init_completion(&ctx->pp_comp);
+	spin_lock_init(&ctx->vsync_lock);
+	atomic_set(&ctx->vsync_ref, 0);
+
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
+				   mdss_mdp_cmd_readptr_done, ctl);
+
+	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+				   mdss_mdp_cmd_pingpong_done, ctl);
+
+	ret = mdss_mdp_cmd_tearcheck_setup(ctl, 1);
+	if (ret) {
+		pr_err("tearcheck setup failed\n");
+		return ret;
+	}
+
+	ctl->stop_fnc = mdss_mdp_cmd_stop;
+	ctl->display_fnc = mdss_mdp_cmd_kickoff;
+	ctl->set_vsync_handler = mdss_mdp_cmd_set_vsync_handler;
+
+	pr_debug("%s:-\n", __func__);
+
+	return 0;
+}
+
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index dab8674..e7f70b6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -242,7 +242,7 @@
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		ctx->timegen_en = false;
 
-		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_OFF, NULL);
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
 		WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc);
 
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
@@ -359,8 +359,8 @@
 				rc, ctl->num);
 
 		ctx->timegen_en = true;
-		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
-		WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
+		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
+		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 0749f0c..5d23315 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -21,6 +21,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 #include <linux/delay.h>
+#include <linux/msm_mdp.h>
 
 #include <mach/iommu_domains.h>
 
@@ -41,8 +42,9 @@
 				struct mdp_overlay *req)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 
-	pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+	pipe = mdss_mdp_pipe_get(mdata, req->id);
 	if (IS_ERR_OR_NULL(pipe)) {
 		pr_err("invalid pipe ndx=%x\n", req->id);
 		return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -60,11 +62,12 @@
 {
 	u32 xres, yres;
 	u32 min_src_size, min_dst_size;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
 
-	if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
 		min_src_size = fmt->is_yuv ? 2 : 1;
 		min_dst_size = 1;
 	} else {
@@ -170,11 +173,12 @@
 static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd,
 					  struct mdp_overlay *req)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_rotator_session *rot;
 	struct mdss_mdp_format_params *fmt;
 	int ret = 0;
 
-	pr_debug("rot ctl=%u req id=%x\n", mfd->ctl->num, req->id);
+	pr_debug("rot ctl=%u req id=%x\n", mdp5_data->ctl->num, req->id);
 
 	fmt = mdss_mdp_get_format_params(req->src.format);
 	if (!fmt) {
@@ -237,9 +241,10 @@
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_mixer *mixer = NULL;
 	u32 pipe_type, mixer_mux, len, src_format;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret;
 
-	if (mfd == NULL || mfd->ctl == NULL)
+	if (mdp5_data->ctl == NULL)
 		return -ENODEV;
 
 	if (req->flags & MDSS_MDP_RIGHT_MIXER)
@@ -247,7 +252,7 @@
 	else
 		mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
 
-	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
+	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mdp5_data->ctl->num, req->id,
 			mixer_mux);
 
 	if (req->flags & MDP_ROT_90) {
@@ -269,14 +274,15 @@
 	if (ret)
 		return ret;
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
+					req->z_order);
 	if (pipe && pipe->ndx != req->id) {
 		pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
 				pipe->num, req->z_order, mixer_mux);
 		pipe->params_changed = true;
 	}
 
-	mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+	mixer = mdss_mdp_mixer_get(mdp5_data->ctl, mixer_mux);
 	if (!mixer) {
 		pr_err("unable to get mixer\n");
 		return -ENODEV;
@@ -310,13 +316,13 @@
 		}
 
 		mutex_lock(&mfd->lock);
-		list_add(&pipe->used_list, &mfd->pipes_used);
+		list_add(&pipe->used_list, &mdp5_data->pipes_used);
 		mutex_unlock(&mfd->lock);
 		pipe->mixer = mixer;
 		pipe->mfd = mfd;
 		pipe->play_cnt = 0;
 	} else {
-		pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+		pipe = mdss_mdp_pipe_get(mdp5_data->mdata, req->id);
 		if (IS_ERR_OR_NULL(pipe)) {
 			pr_err("invalid pipe ndx=%x\n", req->id);
 			return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -406,14 +412,15 @@
 static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
 {
-	int ret = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret;
 
-	ret = mutex_lock_interruptible(&mfd->ov_lock);
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
 	if (ret)
 		return ret;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return -EPERM;
 	}
 
@@ -432,7 +439,7 @@
 		req->z_order -= MDSS_MDP_STAGE_0;
 	}
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -481,16 +488,18 @@
 static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	LIST_HEAD(destroy_pipes);
 
 	mutex_lock(&mfd->lock);
-	list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
+	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
+				cleanup_list) {
 		list_move(&pipe->cleanup_list, &destroy_pipes);
 		mdss_mdp_overlay_free_buf(&pipe->back_buf);
 		mdss_mdp_overlay_free_buf(&pipe->front_buf);
 	}
 
-	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		if (pipe->back_buf.num_planes) {
 			/* make back buffer active */
 			mdss_mdp_overlay_free_buf(&pipe->front_buf);
@@ -595,8 +604,9 @@
 static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
 {
 	int rc;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	if (mfd->ctl->power_on)
+	if (mdp5_data->ctl->power_on)
 		return 0;
 
 	pr_debug("starting fb%d overlay\n", mfd->index);
@@ -608,20 +618,20 @@
 	}
 
 	if (mfd->panel_info->cont_splash_enabled)
-		mdss_mdp_reconfigure_splash_done(mfd->ctl);
+		mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
 
 	if (!is_mdss_iommu_attached()) {
 		mdss_iommu_attach(mdss_res);
 		mdss_hw_init(mdss_res);
 	}
 
-	rc = mdss_mdp_ctl_start(mfd->ctl);
+	rc = mdss_mdp_ctl_start(mdp5_data->ctl);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
 	} else {
 		pr_err("overlay start failed.\n");
-		mdss_mdp_ctl_destroy(mfd->ctl);
-		mfd->ctl = NULL;
+		mdss_mdp_ctl_destroy(mdp5_data->ctl);
+		mdp5_data->ctl = NULL;
 
 		pm_runtime_put(&mfd->pdev->dev);
 	}
@@ -629,15 +639,15 @@
 	return rc;
 }
 
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
 {
-	struct msm_fb_data_type *mfd = ctl->mfd;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
 	int ret;
 
-	mutex_lock(&mfd->ov_lock);
+	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
-	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		if (pipe->back_buf.num_planes) {
 			buf = &pipe->back_buf;
@@ -658,16 +668,17 @@
 		}
 	}
 
-	if (mfd->kickoff_fnc)
-		ret = mfd->kickoff_fnc(ctl);
+	if (mfd->panel.type == WRITEBACK_PANEL)
+		ret = mdss_mdp_wb_kickoff(mfd);
 	else
-		ret = mdss_mdp_display_commit(ctl, NULL);
+		ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
+
 	mutex_unlock(&mfd->lock);
 
 	if (IS_ERR_VALUE(ret))
 		goto commit_fail;
 
-	ret = mdss_mdp_display_wait4comp(ctl);
+	ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
 
 	complete(&mfd->update.comp);
 	mutex_lock(&mfd->no_update.lock);
@@ -681,7 +692,7 @@
 commit_fail:
 	ret = mdss_mdp_overlay_cleanup(mfd);
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -689,6 +700,7 @@
 static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 pipe_ndx, unset_ndx = 0;
 	int i;
 
@@ -696,14 +708,15 @@
 		pipe_ndx = BIT(i);
 		if (pipe_ndx & ndx) {
 			unset_ndx |= pipe_ndx;
-			pipe = mdss_mdp_pipe_get(mfd->mdata, pipe_ndx);
+			pipe = mdss_mdp_pipe_get(mdp5_data->mdata, pipe_ndx);
 			if (IS_ERR_OR_NULL(pipe)) {
 				pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
 				continue;
 			}
 			mutex_lock(&mfd->lock);
 			list_del(&pipe->used_list);
-			list_add(&pipe->cleanup_list, &mfd->pipes_cleanup);
+			list_add(&pipe->cleanup_list,
+				&mdp5_data->pipes_cleanup);
 			mutex_unlock(&mfd->lock);
 			mdss_mdp_mixer_pipe_unstage(pipe);
 			mdss_mdp_pipe_unmap(pipe);
@@ -715,22 +728,23 @@
 static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
 {
 	int ret = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	if (!mfd || !mfd->ctl)
+	if (!mfd || !mdp5_data->ctl)
 		return -ENODEV;
 
-	ret = mutex_lock_interruptible(&mfd->ov_lock);
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
 	if (ret)
 		return ret;
 
 	if (ndx == BORDERFILL_NDX) {
 		pr_debug("borderfill disable\n");
-		mfd->borderfill_enable = false;
+		mdp5_data->borderfill_enable = false;
 		return 0;
 	}
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return -EPERM;
 	}
 
@@ -741,7 +755,7 @@
 	else
 		ret = mdss_mdp_overlay_release(mfd, ndx);
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -749,18 +763,19 @@
 static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 unset_ndx = 0;
 	int cnt = 0;
 
-	mutex_lock(&mfd->ov_lock);
+	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
-	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		unset_ndx |= pipe->ndx;
 		cnt++;
 	}
 
-	if (cnt == 0 && !list_empty(&mfd->pipes_cleanup)) {
-		pr_warn("overlay release on fb%d called without commit!",
+	if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
+		pr_debug("overlay release on fb%d called without commit!",
 			mfd->index);
 		cnt++;
 	}
@@ -771,10 +786,10 @@
 		pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
 		mdss_mdp_overlay_release(mfd, unset_ndx);
 	}
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	if (cnt)
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+		mfd->mdp.kickoff_fnc(mfd);
 
 	return 0;
 }
@@ -782,12 +797,12 @@
 static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd,
 				      struct msmfb_overlay_data *req)
 {
-	int ret;
+	int ret = 0;
 
-	if (!mfd || !mfd->ctl)
+	if (!mfd)
 		return -ENODEV;
 
-	ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+	ret = mfd->mdp.kickoff_fnc(mfd);
 	if (!ret)
 		pr_err("error displaying\n");
 
@@ -840,8 +855,9 @@
 	struct mdss_mdp_data *src_data;
 	int ret;
 	u32 flags;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 
-	pipe = mdss_mdp_pipe_get(mfd->mdata, req->id);
+	pipe = mdss_mdp_pipe_get(mdata, req->id);
 	if (IS_ERR_OR_NULL(pipe)) {
 		pr_err("pipe ndx=%x doesn't exist\n", req->id);
 		return pipe ? PTR_ERR(pipe) : -ENODEV;
@@ -870,16 +886,17 @@
 static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
 				 struct msmfb_overlay_data *req)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret = 0;
 
 	pr_debug("play req id=%x\n", req->id);
 
-	ret = mutex_lock_interruptible(&mfd->ov_lock);
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
 	if (ret)
 		return ret;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return -EPERM;
 	}
 
@@ -893,13 +910,13 @@
 		ret = mdss_mdp_overlay_rotate(mfd, req);
 	} else if (req->id == BORDERFILL_NDX) {
 		pr_debug("borderfill enable\n");
-		mfd->borderfill_enable = true;
+		mdp5_data->borderfill_enable = true;
 		ret = mdss_mdp_overlay_free_fb_pipe(mfd);
 	} else {
 		ret = mdss_mdp_overlay_queue(mfd, req);
 	}
 
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	return ret;
 }
@@ -908,13 +925,16 @@
 {
 	struct mdss_mdp_pipe *pipe;
 	u32 fb_ndx = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT,
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl,
+					MDSS_MDP_MIXER_MUX_LEFT,
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe)
 		fb_ndx |= pipe->ndx;
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, MDSS_MDP_MIXER_MUX_RIGHT,
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl,
+					MDSS_MDP_MIXER_MUX_RIGHT,
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe)
 		fb_ndx |= pipe->ndx;
@@ -930,9 +950,10 @@
 					struct mdss_mdp_pipe **ppipe,
 					int mixer_mux)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
 
-	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
+	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
 					 MDSS_MDP_STAGE_BASE);
 	if (pipe == NULL) {
 		struct mdp_overlay req;
@@ -940,7 +961,8 @@
 		struct mdss_mdp_mixer *mixer;
 		int ret, bpp;
 
-		mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+		mixer = mdss_mdp_mixer_get(mdp5_data->ctl,
+					MDSS_MDP_MIXER_MUX_LEFT);
 		if (!mixer) {
 			pr_err("unable to retrieve mixer\n");
 			return -ENODEV;
@@ -981,7 +1003,7 @@
 		if (ret)
 			return ret;
 
-		pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
+		pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
 	}
 
 	*ppipe = pipe;
@@ -993,24 +1015,25 @@
 	struct mdss_mdp_data data;
 	struct mdss_mdp_pipe *pipe;
 	struct fb_info *fbi;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 offset;
 	int bpp, ret;
 
-	if (!mfd || !mfd->ctl)
+	if (!mfd || !mdp5_data->ctl)
 		return;
 
 	fbi = mfd->fbi;
 
-	if (fbi->fix.smem_len == 0 || mfd->borderfill_enable) {
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+	if (fbi->fix.smem_len == 0 || mdp5_data->borderfill_enable) {
+		mfd->mdp.kickoff_fnc(mfd);
 		return;
 	}
 
-	if (mutex_lock_interruptible(&mfd->ov_lock))
+	if (mutex_lock_interruptible(&mdp5_data->ov_lock))
 		return;
 
 	if (!mfd->panel_power_on) {
-		mutex_unlock(&mfd->ov_lock);
+		mutex_unlock(&mdp5_data->ov_lock);
 		return;
 	}
 
@@ -1076,37 +1099,43 @@
 			goto pan_display_error;
 		}
 	}
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 
 	if ((fbi->var.activate & FB_ACTIVATE_VBL) ||
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
-		mdss_mdp_overlay_kickoff(mfd->ctl);
+		mfd->mdp.kickoff_fnc(mfd);
+
 	return;
 
 pan_display_error:
-	mutex_unlock(&mfd->ov_lock);
+	mutex_unlock(&mdp5_data->ov_lock);
 }
 
 /* function is called in irq context should have minimum processing */
-static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
+						ktime_t t)
 {
 	struct msm_fb_data_type *mfd = ctl->mfd;
-	if (!mfd) {
+	struct mdss_overlay_private *mdp5_data;
+
+	if (!mfd || !mfd->mdp.private1) {
 		pr_warn("Invalid handle for vsync\n");
 		return;
 	}
 
+	mdp5_data = mfd_to_mdp5_data(mfd);
 	pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
 
-	spin_lock(&mfd->vsync_lock);
-	mfd->vsync_time = t;
-	complete(&mfd->vsync_comp);
-	spin_unlock(&mfd->vsync_lock);
+	spin_lock(&mdp5_data->vsync_lock);
+	mdp5_data->vsync_time = t;
+	complete(&mdp5_data->vsync_comp);
+	spin_unlock(&mdp5_data->vsync_lock);
 }
 
 int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
 {
-	struct mdss_mdp_ctl *ctl = mfd->ctl;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	unsigned long flags;
 	int rc;
 
@@ -1122,16 +1151,16 @@
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mfd->vsync_pending = en;
+		mdp5_data->vsync_pending = en;
 		mutex_unlock(&ctl->lock);
 		return 0;
 	}
 
 	pr_debug("fb%d vsync en=%d\n", mfd->index, en);
 
-	spin_lock_irqsave(&mfd->vsync_lock, flags);
-	INIT_COMPLETION(mfd->vsync_comp);
-	spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+	spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
+	INIT_COMPLETION(mdp5_data->vsync_comp);
+	spin_unlock_irqrestore(&mdp5_data->vsync_lock, flags);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (en)
@@ -1150,26 +1179,27 @@
 {
 	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);
 	unsigned long flags;
 	u64 vsync_ticks;
 	unsigned long timeout;
 	int ret;
 
-	if (!mfd->ctl || !mfd->ctl->power_on)
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
 		return 0;
 
 	timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
-	ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
+	ret = wait_for_completion_interruptible_timeout(&mdp5_data->vsync_comp,
 			timeout);
 	if (ret <= 0) {
 		pr_debug("Sending current time as vsync timestamp for fb%d\n",
 				mfd->index);
-		mfd->vsync_time = ktime_get();
+		mdp5_data->vsync_time = ktime_get();
 	}
 
-	spin_lock_irqsave(&mfd->vsync_lock, flags);
-	vsync_ticks = ktime_to_ns(mfd->vsync_time);
-	spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+	spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
+	vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
+	spin_unlock_irqrestore(&mdp5_data->vsync_lock, flags);
 
 	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
 	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
@@ -1191,6 +1221,7 @@
 static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
 				     struct fb_cursor *cursor)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_mixer *mixer;
 	struct fb_image *img = &cursor->image;
 	u32 blendcfg;
@@ -1219,12 +1250,12 @@
 		}
 	}
 
-	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+	mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
 	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
 
 	if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
-	    (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
-	    (img->depth != 32))
+		(img->height > MDSS_MDP_CURSOR_HEIGHT) ||
+		(img->depth != 32))
 		return -EINVAL;
 
 	pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
@@ -1320,13 +1351,227 @@
 	return 0;
 }
 
+static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
+						struct mdp_bl_scale_data *data)
+{
+	int ret = 0;
+	int curr_bl;
+	mutex_lock(&mfd->lock);
+	curr_bl = mfd->bl_level;
+	mfd->bl_scale = data->scale;
+	mfd->bl_min_lvl = data->min_lvl;
+	pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
+							mfd->bl_min_lvl);
+
+	/* update current backlight to use new scaling*/
+	mdss_fb_set_backlight(mfd, curr_bl);
+	mutex_unlock(&mfd->lock);
+	return ret;
+}
+
+static int mdss_mdp_pp_ioctl(struct msm_fb_data_type *mfd,
+				void __user *argp)
+{
+	int ret;
+	struct msmfb_mdp_pp mdp_pp;
+	u32 copyback = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
+	if (ret)
+		return ret;
+
+	switch (mdp_pp.op) {
+	case mdp_op_pa_cfg:
+		ret = mdss_mdp_pa_config(mdp5_data->ctl,
+					&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,
+					&copyback);
+		break;
+
+	case mdp_op_lut_cfg:
+		switch (mdp_pp.data.lut_cfg_data.lut_type) {
+		case mdp_lut_igc:
+			ret = mdss_mdp_igc_lut_config(
+					mdp5_data->ctl,
+					(struct mdp_igc_lut_data *)
+					&mdp_pp.data.lut_cfg_data.data,
+					&copyback);
+			break;
+
+		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;
+
+		default:
+			ret = -ENOTSUPP;
+			break;
+		}
+		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;
+	case mdp_bl_scale_cfg:
+		ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+						&mdp_pp.data.bl_scale_data);
+		break;
+	default:
+		pr_err("Unsupported request to MDP_PP IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	if ((ret == 0) && copyback)
+		ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp));
+	return ret;
+}
+
+static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
+				void __user *argp)
+{
+	int ret = -ENOSYS;
+	struct mdp_histogram_data hist;
+	struct mdp_histogram_start_req hist_req;
+	u32 block, hist_data_addr = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	switch (cmd) {
+	case MSMFB_HISTOGRAM_START:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_start(mdp5_data->ctl, &hist_req);
+		break;
+
+	case MSMFB_HISTOGRAM_STOP:
+		ret = copy_from_user(&block, argp, sizeof(int));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_histogram_stop(mdp5_data->ctl, block);
+		break;
+
+	case MSMFB_HISTOGRAM:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
+		ret = copy_from_user(&hist, argp, sizeof(hist));
+		if (ret)
+			return ret;
+
+		ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist,
+					&hist_data_addr);
+		if ((ret == 0) && hist_data_addr) {
+			ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
+				sizeof(u32) * hist.bin_cnt);
+			if (ret == 0)
+				ret = copy_to_user(argp, &hist,
+						   sizeof(hist));
+		}
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata)
+{
+	int ret = 0;
+	switch (metadata->op) {
+	case metadata_op_vic:
+		if (mfd->panel_info)
+			mfd->panel_info->vic =
+				metadata->data.video_info_code;
+		else
+			ret = -EINVAL;
+		break;
+	default:
+		pr_warn("unsupported request to MDP META IOCTL\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
+		struct mdss_hw_caps *caps)
+{
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	caps->mdp_rev = mdata->mdp_rev;
+	caps->vig_pipes = mdata->nvig_pipes;
+	caps->rgb_pipes = mdata->nrgb_pipes;
+	caps->dma_pipes = mdata->ndma_pipes;
+	return 0;
+}
+
+static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata)
+{
+	int ret = 0;
+	switch (metadata->op) {
+	case metadata_op_frame_rate:
+		metadata->data.panel_frame_rate =
+			mdss_get_panel_framerate(mfd);
+		break;
+	case metadata_op_get_caps:
+		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
+		break;
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
 					  u32 cmd, void __user *argp)
 {
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdp_overlay req;
 	int val, ret = -ENOSYS;
+	struct msmfb_metadata metadata;
 
 	switch (cmd) {
+	case MSMFB_MDP_PP:
+		ret = mdss_mdp_pp_ioctl(mfd, argp);
+		break;
+
+	case MSMFB_HISTOGRAM_START:
+	case MSMFB_HISTOGRAM_STOP:
+	case MSMFB_HISTOGRAM:
+		ret = mdss_mdp_histo_ioctl(mfd, cmd, argp);
+		break;
+
 	case MSMFB_OVERLAY_GET:
 		ret = copy_from_user(&req, argp, sizeof(req));
 		if (!ret) {
@@ -1364,7 +1609,7 @@
 
 	case MSMFB_OVERLAY_PLAY_ENABLE:
 		if (!copy_from_user(&val, argp, sizeof(val))) {
-			mfd->overlay_play_enable = val;
+			mdp5_data->overlay_play_enable = val;
 		} else {
 			pr_err("OVERLAY_PLAY_ENABLE failed (%d)\n", ret);
 			ret = -EFAULT;
@@ -1372,7 +1617,7 @@
 		break;
 
 	case MSMFB_OVERLAY_PLAY:
-		if (mfd->overlay_play_enable) {
+		if (mdp5_data->overlay_play_enable) {
 			struct msmfb_overlay_data data;
 
 			ret = copy_from_user(&data, argp, sizeof(data));
@@ -1392,7 +1637,7 @@
 		break;
 
 	case MSMFB_OVERLAY_PLAY_WAIT:
-		if (mfd->overlay_play_enable) {
+		if (mdp5_data->overlay_play_enable) {
 			struct msmfb_overlay_data data;
 
 			ret = copy_from_user(&data, argp, sizeof(data));
@@ -1419,9 +1664,23 @@
 		break;
 	case MSMFB_OVERLAY_COMMIT:
 		mdss_fb_wait_for_fence(mfd);
-		ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+		ret = mfd->mdp.kickoff_fnc(mfd);
 		mdss_fb_signal_timeline(mfd);
 		break;
+	case MSMFB_METADATA_SET:
+		ret = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (ret)
+			return ret;
+		ret = mdss_fb_set_metadata(mfd, &metadata);
+		break;
+	case MSMFB_METADATA_GET:
+		ret = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (ret)
+			return ret;
+		ret = mdss_fb_get_metadata(mfd, &metadata);
+		if (!ret)
+			ret = copy_to_user(argp, &metadata, sizeof(metadata));
+		break;
 	default:
 		if (mfd->panel.type == WRITEBACK_PANEL)
 			ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -1433,7 +1692,8 @@
 
 static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
 {
-	int rc = 0;
+	int rc;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	if (!mfd)
 		return -ENODEV;
@@ -1441,7 +1701,7 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	if (!mfd->ctl) {
+	if (!mdp5_data->ctl) {
 		struct mdss_mdp_ctl *ctl;
 		struct mdss_panel_data *pdata;
 
@@ -1466,22 +1726,22 @@
 				return rc;
 			}
 		}
-		mfd->ctl = ctl;
+		mdp5_data->ctl = ctl;
 	}
 
 	if (!mfd->panel_info->cont_splash_enabled) {
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL))
-			rc = mdss_mdp_overlay_kickoff(mfd->ctl);
+			rc = mdss_mdp_overlay_kickoff(mfd);
 	} else {
-		rc = mdss_mdp_ctl_setup(mfd->ctl);
+		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
 		if (rc)
 			return rc;
 	}
 
-	if (!IS_ERR_VALUE(rc) && mfd->vsync_pending) {
-		mfd->vsync_pending = 0;
-		mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+	if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+		mdp5_data->vsync_pending = 0;
+		mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
 	}
 
 	return rc;
@@ -1490,6 +1750,7 @@
 static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd)
 {
 	int rc;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 
 	if (!mfd)
 		return -ENODEV;
@@ -1497,22 +1758,22 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	if (!mfd->ctl) {
+	if (!mdp5_data->ctl) {
 		pr_err("ctl not initialized\n");
 		return -ENODEV;
 	}
 
-	if (!mfd->ctl->power_on)
+	if (!mdp5_data->ctl->power_on)
 		return 0;
 
 	mdss_mdp_overlay_release_all(mfd);
 
-	rc = mdss_mdp_ctl_stop(mfd->ctl);
+	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
 	if (rc == 0) {
 		if (!mfd->ref_cnt) {
-			mfd->borderfill_enable = false;
-			mdss_mdp_ctl_destroy(mfd->ctl);
-			mfd->ctl = NULL;
+			mdp5_data->borderfill_enable = false;
+			mdss_mdp_ctl_destroy(mdp5_data->ctl);
+			mdp5_data->ctl = NULL;
 		}
 
 		if (atomic_dec_return(&ov_active_panels) == 0)
@@ -1526,39 +1787,63 @@
 	return rc;
 }
 
+int mdss_panel_register_done(struct mdss_panel_data *pdata)
+{
+	/*
+	 * Clocks are already on if continuous splash is enabled,
+	 * increasing ref_cnt to help balance clocks once done.
+	 */
+	if (pdata->panel_info.cont_splash_enabled) {
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		mdss_mdp_footswitch_ctrl_splash(1);
+		mdss_mdp_copy_splash_screen(pdata);
+	}
+	return 0;
+}
+
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
+	struct msm_mdp_interface *mdp5_interface = &mfd->mdp;
+	struct mdss_overlay_private *mdp5_data = NULL;
 	int rc;
 
-	mfd->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
-	if (!mfd->mdata) {
-		pr_err("unable to initialize overlay for fb%d\n", mfd->index);
-		return -ENODEV;
+	mdp5_interface->on_fnc = mdss_mdp_overlay_on;
+	mdp5_interface->off_fnc = mdss_mdp_overlay_off;
+	mdp5_interface->do_histogram = NULL;
+	mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
+	mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
+	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_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
+	if (!mdp5_data) {
+		pr_err("fail to allocate mdp5 private data structure");
+		return -ENOMEM;
 	}
+	memset(mdp5_data, 0, sizeof(struct mdss_overlay_private));
 
-	mfd->on_fnc = mdss_mdp_overlay_on;
-	mfd->off_fnc = mdss_mdp_overlay_off;
-	mfd->hw_refresh = true;
-	mfd->do_histogram = NULL;
-	mfd->overlay_play_enable = true;
-	mfd->cursor_update = mdss_mdp_hw_cursor_update;
-	mfd->dma_fnc = mdss_mdp_overlay_pan_display;
-	mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+	INIT_LIST_HEAD(&mdp5_data->pipes_used);
+	INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
+	init_completion(&mdp5_data->vsync_comp);
+	spin_lock_init(&mdp5_data->vsync_lock);
+	mutex_init(&mdp5_data->ov_lock);
+	mdp5_data->hw_refresh = true;
+	mdp5_data->overlay_play_enable = true;
 
-	if (mfd->panel.type == WRITEBACK_PANEL)
-		mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
-
-	INIT_LIST_HEAD(&mfd->pipes_used);
-	INIT_LIST_HEAD(&mfd->pipes_cleanup);
-	init_completion(&mfd->vsync_comp);
-	spin_lock_init(&mfd->vsync_lock);
-	mutex_init(&mfd->ov_lock);
+	mdp5_data->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
+	if (!mdp5_data->mdata) {
+		pr_err("unable to initialize overlay for fb%d\n", mfd->index);
+		rc = -ENODEV;
+		goto init_fail;
+	}
+	mfd->mdp.private1 = mdp5_data;
 
 	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
 	if (rc) {
 		pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
-		return rc;
+		goto init_fail;
 	}
 
 	pm_runtime_set_suspended(&mfd->pdev->dev);
@@ -1568,4 +1853,7 @@
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
 	return rc;
+init_fail:
+	kfree(mdp5_data);
+	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b54e0ec..8ce5ab5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -42,6 +42,9 @@
 	MDP_INTR_PING_PONG_0,
 	MDP_INTR_PING_PONG_1,
 	MDP_INTR_PING_PONG_2,
+	MDP_INTR_PING_PONG_0_RD_PTR,
+	MDP_INTR_PING_PONG_1_RD_PTR,
+	MDP_INTR_PING_PONG_2_RD_PTR,
 	MDP_INTR_WB_0,
 	MDP_INTR_WB_1,
 	MDP_INTR_WB_2,
@@ -69,6 +72,9 @@
 	case MDSS_MDP_IRQ_PING_PONG_COMP:
 		index = MDP_INTR_PING_PONG_0 + intf_num;
 		break;
+	case MDSS_MDP_IRQ_PING_PONG_RD_PTR:
+		index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num;
+		break;
 	case MDSS_MDP_IRQ_WB_ROT_COMP:
 		index = MDP_INTR_WB_0 + intf_num;
 		break;
@@ -126,11 +132,12 @@
 	if (isr == 0)
 		goto mdp_isr_done;
 
-	pr_debug("isr=%x\n", isr);
 
 	mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
 	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
 
+	pr_debug("%s: isr=%x mask=%x\n", __func__, isr, mask);
+
 	isr &= mask;
 	if (isr == 0)
 		goto mdp_isr_done;
@@ -156,6 +163,15 @@
 	if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
 		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
 
+	if (isr & MDSS_MDP_INTR_PING_PONG_0_RD_PTR)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_RD_PTR);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_1_RD_PTR)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_RD_PTR);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
+
 	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
 		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index d24a7c9..88e7605 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -124,18 +124,13 @@
 
 int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable)
 {
-	struct mdss_mdp_wb *wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_mixer *mixer;
 
 	pr_debug("setting secure=%d\n", enable);
 
-	wb = mfd->wb;
-	if (wb == NULL) {
-		pr_err("Invalid writeback session\n");
-		return -ENODEV;
-	}
-
 	wb->is_secure = enable;
 	pipe = wb->secure_pipe;
 
@@ -149,7 +144,7 @@
 		return 0;
 	}
 
-	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
 	if (!mixer) {
 		pr_err("Unable to find mixer for wb\n");
 		return -ENOENT;
@@ -190,14 +185,14 @@
 
 static int mdss_mdp_wb_init(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	mutex_lock(&mdss_mdp_wb_buf_lock);
-	wb = mfd->wb;
 	if (wb == NULL) {
 		wb = &mdss_mdp_wb_info;
 		wb->fb_ndx = mfd->index;
-		mfd->wb = wb;
+		mdp5_data->wb = wb;
 	} else if (mfd->index != wb->fb_ndx) {
 		pr_err("only one writeback intf supported at a time\n");
 		return -EMLINK;
@@ -214,14 +209,15 @@
 	wb->state = WB_OPEN;
 	init_waitqueue_head(&wb->wait_q);
 
-	mfd->wb = wb;
+	mdp5_data->wb = wb;
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
 	return 0;
 }
 
 static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	if (!wb) {
 		pr_err("unable to terminate, writeback is not initialized\n");
@@ -246,7 +242,7 @@
 		mdss_mdp_pipe_destroy(wb->secure_pipe);
 	mutex_unlock(&wb->lock);
 
-	mfd->wb = NULL;
+	mdp5_data->wb = NULL;
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
 
 	return 0;
@@ -254,7 +250,7 @@
 
 static int mdss_mdp_wb_start(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	if (!wb) {
 		pr_err("unable to start, writeback is not initialized\n");
@@ -271,7 +267,7 @@
 
 static int mdss_mdp_wb_stop(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 
 	if (!wb) {
 		pr_err("unable to stop, writeback is not initialized\n");
@@ -343,8 +339,10 @@
 }
 
 static struct mdss_mdp_wb_data *get_user_node(struct msm_fb_data_type *mfd,
-					      struct msmfb_data *data) {
-	struct mdss_mdp_wb *wb = mfd->wb;
+						struct msmfb_data *data)
+{
+
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node;
 	struct mdss_mdp_img_data *buf;
 	int ret;
@@ -383,9 +381,9 @@
 }
 
 static int mdss_mdp_wb_queue(struct msm_fb_data_type *mfd,
-			     struct msmfb_data *data, int local)
+				struct msmfb_data *data, int local)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret = 0;
 
@@ -426,9 +424,9 @@
 }
 
 static int mdss_mdp_wb_dequeue(struct msm_fb_data_type *mfd,
-			       struct msmfb_data *data)
+				struct msmfb_data *data)
 {
-	struct mdss_mdp_wb *wb = mfd->wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret;
 
@@ -473,9 +471,10 @@
 		complete((struct completion *) arg);
 }
 
-int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd)
 {
-	struct mdss_mdp_wb *wb;
+	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
 	int ret = 0;
 	DECLARE_COMPLETION_ONSTACK(comp);
@@ -484,14 +483,10 @@
 		.priv_data = &comp,
 	};
 
-	if (!ctl || !ctl->mfd)
-		return -ENODEV;
-
 	if (!ctl->power_on)
 		return 0;
 
 	mutex_lock(&mdss_mdp_wb_buf_lock);
-	wb = ctl->mfd->wb;
 	if (wb) {
 		mutex_lock(&wb->lock);
 		/* in case of reinit of control path need to reset secure */
@@ -540,7 +535,8 @@
 	return ret;
 }
 
-int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg)
+int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd,
+				void *arg)
 {
 	struct msmfb_data data;
 	int ret = -ENOSYS;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 31fb2e7..23f7445 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -58,9 +58,9 @@
 enum mdss_intf_events {
 	MDSS_EVENT_RESET,
 	MDSS_EVENT_UNBLANK,
-	MDSS_EVENT_TIMEGEN_ON,
+	MDSS_EVENT_PANEL_ON,
 	MDSS_EVENT_BLANK,
-	MDSS_EVENT_TIMEGEN_OFF,
+	MDSS_EVENT_PANEL_OFF,
 	MDSS_EVENT_CLOSE,
 	MDSS_EVENT_SUSPEND,
 	MDSS_EVENT_RESUME,
@@ -69,19 +69,7 @@
 	MDSS_EVENT_FB_REGISTERED,
 };
 
-/* panel info type */
 struct lcd_panel_info {
-	u32 vsync_enable;
-	u32 refx100;
-	u32 v_back_porch;
-	u32 v_front_porch;
-	u32 v_pulse_width;
-	u32 hw_vsync_mode;
-	u32 vsync_notifier_period;
-	u32 rev;
-};
-
-struct lcdc_panel_info {
 	u32 h_back_porch;
 	u32 h_front_porch;
 	u32 h_pulse_width;
@@ -153,6 +141,9 @@
 	char no_max_pkt_size;
 	/* Clock required during LP commands */
 	char force_clk_lane_hs;
+
+	char vsync_enable;
+	char hw_vsync_mode;
 };
 
 enum lvds_mode {
@@ -183,13 +174,16 @@
 	u32 is_3d_panel;
 	u32 out_format;
 	u32 vic; /* video identification code */
+	int bklt_ctrl;	/* backlight ctrl */
+	int pwm_gpio;
+	int pwm_lpg_chan;
+	int pwm_period;
 
 	u32 cont_splash_enabled;
 	struct ion_handle *splash_ihdl;
 	u32 panel_power_on;
 
-	struct lcd_panel_info lcd;
-	struct lcdc_panel_info lcdc;
+	struct lcd_panel_info lcdc;
 	struct mipi_panel_info mipi;
 	struct lvds_panel_info lvds;
 };
diff --git a/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
index 647504f..be02113 100644
--- a/drivers/video/msm/mdss/mdss_qpic.c
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -113,11 +113,24 @@
 		(u32 *)fb_offset, size);
 }
 
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
-			u32 size, u32 *phys, void **virt)
+int mdss_qpic_alloc_fb_mem(struct msm_fb_data_type *mfd)
 {
+	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
 	if (!qpic_res->res_init)
 		return -EINVAL;
+
+	if (mfd->index != 0) {
+		mfd->fbi->fix.smem_start = 0;
+		mfd->fbi->screen_base = NULL;
+		mfd->fbi->fix.smem_len = 0;
+		mfd->iova = 0;
+		return 0;
+	}
+
 	if (!qpic_res->fb_virt) {
 		qpic_res->fb_virt = (void *)dmam_alloc_coherent(
 						&qpic_res->pdev->dev,
@@ -132,29 +145,31 @@
 		qpic_res->cmd_buf_virt = qpic_res->fb_virt + size;
 		qpic_res->cmd_buf_phys = qpic_res->fb_phys + size;
 	}
-	*phys = qpic_res->fb_phys;
-	*virt = qpic_res->fb_virt;
+	mfd->fbi->fix.smem_start = qpic_res->fb_phys;
+	mfd->fbi->screen_base = qpic_res->fb_virt;
+	mfd->fbi->fix.smem_len = size;
+	mfd->iova = 0;
 	return 0;
 }
 
-u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
+u32 mdss_qpic_fb_stride(u32 fb_index, u32 xres, int bpp)
 {
 	return xres * bpp;
 }
 
-int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+int mdss_qpic_overlay_init(struct msm_fb_data_type *mfd)
 {
-	mfd->on_fnc = qpic_on;
-	mfd->off_fnc = qpic_off;
-	mfd->dma_fnc = mdss_qpic_pan_display;
+	struct msm_mdp_interface *qpic_interface = &mfd->mdp;
+	qpic_interface->on_fnc = qpic_on;
+	qpic_interface->off_fnc = qpic_off;
+	qpic_interface->do_histogram = NULL;
+	qpic_interface->cursor_update = NULL;
+	qpic_interface->dma_fnc = mdss_qpic_pan_display;
+	qpic_interface->ioctl_handler = NULL;
+	qpic_interface->kickoff_fnc = NULL;
 	return 0;
 }
 
-u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
-{
-	return qpic_panel_get_framerate();
-}
-
 int qpic_register_panel(struct mdss_panel_data *pdata)
 {
 	struct platform_device *mdss_fb_dev = NULL;
@@ -511,6 +526,12 @@
 {
 	struct resource *res;
 	int rc = 0;
+	static struct msm_mdp_interface qpic_interface = {
+		.init_fnc = mdss_qpic_overlay_init,
+		.fb_mem_alloc_fnc = mdss_qpic_alloc_fb_mem,
+		.fb_stride = mdss_qpic_fb_stride,
+	};
+
 
 	if (!pdev->dev.of_node) {
 		pr_err("qpic driver only supports device tree probe\n");
@@ -564,6 +585,11 @@
 
 	qpic_res->irq = res->start;
 	qpic_res->res_init = true;
+
+	rc = mdss_fb_register_mdp_instance(&qpic_interface);
+	if (rc)
+		pr_err("unable to register QPIC instance\n");
+
 probe_done:
 	return rc;
 }
@@ -585,124 +611,4 @@
 
 module_init(mdss_qpic_driver_init);
 
-int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_pa_cfg_data *config, u32 *copyback)
-{
-	return 0;
-}
 
-int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_igc_lut_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_pgc_lut_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_hist_lut_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_dither_cfg_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
-	struct mdp_gamut_cfg_data *config, u32 *copyback)
-{
-	return 0;
-}
-
-int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
-	struct mdp_histogram_start_req *req)
-{
-	return 0;
-}
-
-int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
-{
-	return 0;
-}
-
-int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
-				struct mdp_histogram_data *hist,
-				u32 *hist_data_addr)
-{
-	return 0;
-}
-
-int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
-{
-	return 0;
-}
-
-void mdss_mdp_clk_ctrl(int enable, int isr)
-{
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
-	return 0;
-}
-
-void mdss_mdp_footswitch_ctrl_splash(int on)
-{
-}
-
-int msm_fb_writeback_init(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_init);
-
-int msm_fb_writeback_start(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_start);
-
-int msm_fb_writeback_queue_buffer(struct fb_info *info,
-		struct msmfb_data *data)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_queue_buffer);
-
-int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
-		struct msmfb_data *data)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer);
-
-int msm_fb_writeback_stop(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_stop);
-
-int msm_fb_writeback_terminate(struct fb_info *info)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_writeback_terminate);
-
-int msm_fb_get_iommu_domain(struct fb_info *info, int domain)
-{
-	return 0;
-}
-EXPORT_SYMBOL(msm_fb_get_iommu_domain);
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7939832..969b400 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -20,6 +20,7 @@
 #define DEINIT_TYPE			16
 #define USER_SPACE_DATA_TYPE		32
 #define DCI_DATA_TYPE			64
+#define CALLBACK_DATA_TYPE		128
 #define USB_MODE			1
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
diff --git a/include/linux/ion.h b/include/linux/ion.h
index fb1c5f6..7c54004 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -59,6 +59,9 @@
 					   cached, ion will do cache
 					   maintenance when the buffer is
 					   mapped for dma */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2	/* mappings of this buffer will created
+					   at mmap time, if this is set
+					   caches must be managed manually */
 
 #ifdef __KERNEL__
 #include <linux/err.h>
@@ -606,6 +609,16 @@
 #define ION_IOC_IMPORT		_IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
 
 /**
+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
+ *
+ * Deprecated in favor of using the dma_buf api's correctly (syncing
+ * will happend automatically when the buffer is mapped to a device).
+ * If necessary should be used after touching a cached buffer from the cpu,
+ * this will make the buffer in memory coherent.
+ */
+#define ION_IOC_SYNC		_IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+
+/**
  * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
  *
  * Takes the argument of the architecture specific ioctl to call and
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index fa97ba9..98ec93f 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -224,6 +224,16 @@
  * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
  */
 int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable);
+
+/**
+ * pm8xxx_read_register - Read a PMIC register
+ * @addr: PMIC register address
+ * @value: Output parameter which gets the value of the register read.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_read_register(u16 addr, u8 *value);
+
 #else
 
 static inline int pm8xxx_reset_pwr_off(int reset)
@@ -278,6 +288,10 @@
 {
 	return -ENODEV;
 }
+static inline int pm8xxx_read_register(u16 addr, u8 *value)
+{
+	return -ENODEV;
+}
 
 #endif
 
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 9461c76..5e6a8c3 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -46,6 +46,14 @@
  * @ocv_dis_low_soc:		the low soc percent when ocv should be enabled
  * @low_voltage_detect:		feature to enable 0 SOC reporting on low volatge
  * @vbatt_cutoff_retries:	number of tries before we report a 0 SOC
+ * @high_ocv_correction_limit_uv:	the max amount of OCV corrections
+ *					allowed when ocv is high
+ *					(higher than 3.8V)
+ * @low_ocv_correction_limit_uv:	the max amount of OCV corrections
+ *					allowed when ocv is low
+ *					(lower or equal to 3.8V)
+ * @hold_soc_est:		the min est soc below which the calculated soc
+ *				is allowed to go to 0%
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
@@ -69,6 +77,9 @@
 	int				ocv_dis_low_soc;
 	int				low_voltage_detect;
 	int				vbatt_cutoff_retries;
+	int				high_ocv_correction_limit_uv;
+	int				low_ocv_correction_limit_uv;
+	int				hold_soc_est;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca7a586..5dc65bd 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -61,14 +61,6 @@
 	MIGRATE_TYPES
 };
 
-/*
- * Returns a list which contains the migrate types on to which
- * an allocation falls back when the free list for the migrate
- * type mtype is depleted.
- * The end of the list is delimited by the type MIGRATE_RESERVE.
- */
-extern int *get_migratetype_fallbacks(int mtype);
-
 #ifdef CONFIG_CMA
 bool is_cma_pageblock(struct page *page);
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index b7d393f..307be2b 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -200,6 +200,26 @@
 	unsigned int dev_minor;
 };
 
+/* Performance counter groups */
+
+#define KGSL_PERFCOUNTER_GROUP_CP 0x0
+#define KGSL_PERFCOUNTER_GROUP_RBBM 0x1
+#define KGSL_PERFCOUNTER_GROUP_PC 0x2
+#define KGSL_PERFCOUNTER_GROUP_VFD 0x3
+#define KGSL_PERFCOUNTER_GROUP_HLSQ 0x4
+#define KGSL_PERFCOUNTER_GROUP_VPC 0x5
+#define KGSL_PERFCOUNTER_GROUP_TSE 0x6
+#define KGSL_PERFCOUNTER_GROUP_RAS 0x7
+#define KGSL_PERFCOUNTER_GROUP_UCHE 0x8
+#define KGSL_PERFCOUNTER_GROUP_TP 0x9
+#define KGSL_PERFCOUNTER_GROUP_SP 0xA
+#define KGSL_PERFCOUNTER_GROUP_RB 0xB
+#define KGSL_PERFCOUNTER_GROUP_PWR 0xC
+#define KGSL_PERFCOUNTER_GROUP_VBIF 0xD
+#define KGSL_PERFCOUNTER_GROUP_VBIF_PWR 0xE
+
+#define KGSL_PERFCOUNTER_NOT_USED 0xFFFFFFFF
+
 /* structure holds list of ibs */
 struct kgsl_ibdesc {
 	unsigned int gpuaddr;
@@ -650,6 +670,110 @@
 #define IOCTL_KGSL_GPUMEM_SYNC_CACHE \
 	_IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache)
 
+/**
+ * struct kgsl_perfcounter_get - argument to IOCTL_KGSL_PERFCOUNTER_GET
+ * @groupid: Performance counter group ID
+ * @countable: Countable to select within the group
+ * @offset: Return offset of the reserved counter
+ *
+ * Get an available performance counter from a specified groupid.  The offset
+ * of the performance counter will be returned after successfully assigning
+ * the countable to the counter for the specified group.  An error will be
+ * returned and an offset of 0 if the groupid is invalid or there are no
+ * more counters left.  After successfully getting a perfcounter, the user
+ * must call kgsl_perfcounter_put(groupid, contable) when finished with
+ * the perfcounter to clear up perfcounter resources.
+ *
+ */
+struct kgsl_perfcounter_get {
+	unsigned int groupid;
+	unsigned int countable;
+	unsigned int offset;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_GET \
+	_IOWR(KGSL_IOC_TYPE, 0x38, struct kgsl_perfcounter_get)
+
+/**
+ * struct kgsl_perfcounter_put - argument to IOCTL_KGSL_PERFCOUNTER_PUT
+ * @groupid: Performance counter group ID
+ * @countable: Countable to release within the group
+ *
+ * Put an allocated performance counter to allow others to have access to the
+ * resource that was previously taken.  This is only to be called after
+ * successfully getting a performance counter from kgsl_perfcounter_get().
+ *
+ */
+struct kgsl_perfcounter_put {
+	unsigned int groupid;
+	unsigned int countable;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_PUT \
+	_IOW(KGSL_IOC_TYPE, 0x39, struct kgsl_perfcounter_put)
+
+/**
+ * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY
+ * @groupid: Performance counter group ID
+ * @countable: Return active countables array
+ * @size: Size of active countables array
+ * @max_counters: Return total number counters for the group ID
+ *
+ * Query the available performance counters given a groupid.  The array
+ * *countables is used to return the current active countables in counters.
+ * The size of the array is passed in so the kernel will only write at most
+ * size or counter->size for the group id.  The total number of available
+ * counters for the group ID is returned in max_counters.
+ * If the array or size passed in are invalid, then only the maximum number
+ * of counters will be returned, no data will be written to *countables.
+ * If the groupid is invalid an error code will be returned.
+ *
+ */
+struct kgsl_perfcounter_query {
+	unsigned int groupid;
+	/* Array to return the current countable for up to size counters */
+	unsigned int *countables;
+	unsigned int count;
+	unsigned int max_counters;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_QUERY \
+	_IOWR(KGSL_IOC_TYPE, 0x3A, struct kgsl_perfcounter_query)
+
+/**
+ * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY
+ * @groupid: Performance counter group IDs
+ * @countable: Performance counter countable IDs
+ * @value: Return performance counter reads
+ * @size: Size of all arrays (groupid/countable pair and return value)
+ *
+ * Read in the current value of a performance counter given by the groupid
+ * and countable.
+ *
+ */
+
+struct kgsl_perfcounter_read_group {
+	unsigned int groupid;
+	unsigned int countable;
+	uint64_t value;
+};
+
+struct kgsl_perfcounter_read {
+	struct kgsl_perfcounter_read_group *reads;
+	unsigned int count;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_PERFCOUNTER_READ \
+	_IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
+
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0ab5143..84e099d 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1704,9 +1704,14 @@
  * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
  * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
  * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
  * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -1715,6 +1720,11 @@
 	NL80211_RATE_INFO_MCS,
 	NL80211_RATE_INFO_40_MHZ_WIDTH,
 	NL80211_RATE_INFO_SHORT_GI,
+	NL80211_RATE_INFO_VHT_MCS,
+	NL80211_RATE_INFO_VHT_NSS,
+	NL80211_RATE_INFO_80_MHZ_WIDTH,
+	NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+	NL80211_RATE_INFO_160_MHZ_WIDTH,
 
 	/* keep last */
 	__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index fc6ab91..15e5dc9 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1359,6 +1359,12 @@
 int32_t qpnp_iadc_vadc_sync_read(
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
+/**
+ * qpnp_iadc_calibrate_for_trim() - Clients can use this API to re-calibrate
+ *		IADC.
+ * @result:	0 on success.
+ */
+int32_t qpnp_iadc_calibrate_for_trim(void);
 #else
 static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 						struct qpnp_iadc_result *result)
@@ -1374,6 +1380,8 @@
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_calibrate_for_trim(void)
+{ return -ENXIO; }
 #endif
 
 /* Public API */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 52811ae..bfa0eca 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -578,14 +578,24 @@
  * Used by the driver to indicate the specific rate transmission
  * type for 802.11n transmissions.
  *
- * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
+ * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
+ * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
+ * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
+ * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
  * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
+ * @RATE_INFO_FLAGS_60G: 60GHz MCS
  */
 enum rate_info_flags {
-	RATE_INFO_FLAGS_MCS		= 1<<0,
-	RATE_INFO_FLAGS_40_MHZ_WIDTH	= 1<<1,
-	RATE_INFO_FLAGS_SHORT_GI	= 1<<2,
+	RATE_INFO_FLAGS_MCS			= BIT(0),
+	RATE_INFO_FLAGS_VHT_MCS			= BIT(1),
+	RATE_INFO_FLAGS_40_MHZ_WIDTH		= BIT(2),
+	RATE_INFO_FLAGS_80_MHZ_WIDTH		= BIT(3),
+	RATE_INFO_FLAGS_80P80_MHZ_WIDTH		= BIT(4),
+	RATE_INFO_FLAGS_160_MHZ_WIDTH		= BIT(5),
+	RATE_INFO_FLAGS_SHORT_GI		= BIT(6),
+	RATE_INFO_FLAGS_60G			= BIT(7),
 };
 
 /**
@@ -596,11 +606,13 @@
  * @flags: bitflag of flags from &enum rate_info_flags
  * @mcs: mcs index if struct describes a 802.11n bitrate
  * @legacy: bitrate in 100kbit/s for 802.11abg
+ * @nss: number of streams (VHT only)
  */
 struct rate_info {
 	u8 flags;
 	u8 mcs;
 	u16 legacy;
+	u8 nss;
 };
 
 /**
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d6dd07a..b179e71 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -926,11 +926,6 @@
 	[MIGRATE_ISOLATE]     = { MIGRATE_RESERVE }, /* Never used */
 };
 
-int *get_migratetype_fallbacks(int mtype)
-{
-	return fallbacks[mtype];
-}
-
 /*
  * Move the free pages in a range to the free lists of the requested type.
  * Note that start_page and end_pages are not aligned on a pageblock
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 69318b0..5097036 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2384,25 +2384,46 @@
 
 	rate = nla_nest_start(msg, attr);
 	if (!rate)
-		goto nla_put_failure;
+		return false;
 
 	/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
 	bitrate = cfg80211_calculate_bitrate(info);
 	if (bitrate > 0)
-		NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
+		nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
 
-	if (info->flags & RATE_INFO_FLAGS_MCS)
-		NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
-	if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
-		NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
-	if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
-		NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+	if (info->flags & RATE_INFO_FLAGS_MCS) {
+		if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+			return false;
+	} else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
+		if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
+			return false;
+		if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
+			return false;
+		if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+		    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+			return false;
+	}
 
 	nla_nest_end(msg, rate);
 	return true;
-
-nla_put_failure:
-	return false;
 }
 
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 017d4fc..b89fb94 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -876,13 +876,86 @@
 	return err;
 }
 
+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+	static const u32 base[4][10] = {
+		{   6500000,
+		   13000000,
+		   19500000,
+		   26000000,
+		   39000000,
+		   52000000,
+		   58500000,
+		   65000000,
+		   78000000,
+		   0,
+		},
+		{  13500000,
+		   27000000,
+		   40500000,
+		   54000000,
+		   81000000,
+		  108000000,
+		  121500000,
+		  135000000,
+		  162000000,
+		  180000000,
+		},
+		{  29300000,
+		   58500000,
+		   87800000,
+		  117000000,
+		  175500000,
+		  234000000,
+		  263300000,
+		  292500000,
+		  351000000,
+		  390000000,
+		},
+		{  58500000,
+		  117000000,
+		  175500000,
+		  234000000,
+		  351000000,
+		  468000000,
+		  526500000,
+		  585000000,
+		  702000000,
+		  780000000,
+		},
+	};
+	u32 bitrate;
+	int idx;
+
+	if (WARN_ON_ONCE(rate->mcs > 9))
+		return 0;
+
+	idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+			     RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+		  rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+		  rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+	bitrate = base[idx][rate->mcs];
+	bitrate *= rate->nss;
+
+	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
 u16 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
 	int modulation, streams, bitrate;
 
-	if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+	if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+	    !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
 		return rate->legacy;
 
+	if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+		return cfg80211_calculate_bitrate_vht(rate);
+
 	/* the formula below does only work for MCS values smaller than 32 */
 	if (rate->mcs >= 32)
 		return 0;
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 8c0d1a9..65b3a57 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -746,21 +746,21 @@
 	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
 	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_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] = 21;
+	btn_low[1] = 22;
+	btn_high[1] = 67;
+	btn_low[2] = 68;
+	btn_high[2] = 111;
+	btn_low[3] = 112;
+	btn_high[3] = 153;
+	btn_low[4] = 154;
+	btn_high[4] = 191;
+	btn_low[5] = 192;
+	btn_high[5] = 233;
+	btn_low[6] = 234;
+	btn_high[6] = 272;
+	btn_low[7] = 273;
+	btn_high[7] = 400;
 	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
 	n_ready[0] = 80;
 	n_ready[1] = 68;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 3b1727c..fed0d81 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2363,11 +2363,11 @@
 static void config_debug_fs_init(void)
 {
 	debugfs_afelb = debugfs_create_file("afe_loopback",
-	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+	S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback",
 	&afe_debug_fops);
 
 	debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
-	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+	S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback_gain",
 	&afe_debug_fops);
 }
 static void config_debug_fs_exit(void)
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ea2b5c6..49b6d03 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -279,13 +279,13 @@
 {
 	out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
 	out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
-				S_IFREG | S_IRUGO | S_IWUGO,\
+				S_IRUGO | S_IWUSR | S_IWGRP,\
 				NULL, NULL, &audio_output_latency_debug_fops);
 	if (IS_ERR(out_dentry))
 		pr_err("debugfs_create_file failed\n");
 	in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
 	in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
-				S_IFREG | S_IRUGO | S_IWUGO,\
+				S_IRUGO | S_IWUSR | S_IWGRP,\
 				NULL, NULL, &audio_input_latency_debug_fops);
 	if (IS_ERR(in_dentry))
 		pr_err("debugfs_create_file failed\n");