Merge "msm: vidc: Add support for thumbnail mode"
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 0b30c26..380fde1 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -127,7 +127,7 @@
 	struct list_head req_list;
 	struct work_struct work;
 	int prio;
-	int pending;
+	atomic_t pending;
 	bool passive;
 };
 
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 5a85eec..3d9639f 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -404,7 +404,7 @@
 	if (offset < 0)
 		return -EINVAL;
 
-	if (len < region_size)
+	if (len < OCMEM_MIN_ALLOC)
 		return -EINVAL;
 
 	pr_debug("ocmem: mode_transistion to %x\n", new_mode);
@@ -425,7 +425,7 @@
 			/* Set the region to its new mode */
 			region->mode = new_mode;
 			atomic_inc(&region->mode_counter);
-			pr_debug("Region  (%d) switching to mode %d\n",
+			pr_debug("Region (%d) switching to mode %d\n",
 					i, new_mode);
 			continue;
 		} else if (region->mode != new_mode) {
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4aba69c..818a20a 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -58,6 +58,7 @@
 #define BR_CLIENT_n_IDX(x) ((x) * 0x4)
 #define BR_CLIENT_n_ctrl(x) (BR_CLIENT_BASE + (BR_CLIENT_n_IDX(x)))
 #define BR_STATUS (0x14)
+#define BR_LAST_ADDR (0x18)
 /* 16 entries per client are supported */
 /* Use entries 0 - 15 for client0 */
 #define BR_CLIENT0_MASK	(0x1000)
@@ -76,7 +77,7 @@
 #define BR_TBL_ENTRY_ENABLE 0x1
 #define BR_TBL_START 0x0
 #define BR_TBL_END 0x8
-#define BR_RW_SHIFT 0x2
+#define BR_RW_SHIFT 0x1
 
 #define DM_TBL_START 0x10
 #define DM_TBL_END 0x18
@@ -134,13 +135,13 @@
 	pr_debug("irq:dm_status %x irq_status %x\n", status, irq_status);
 	if (irq_status & BIT(0)) {
 		pr_debug("Data mover completed\n");
-		irq_status &= ~BIT(0);
-		ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+		ocmem_write(BIT(0), dm_base + DM_INTR_CLR);
+		pr_debug("Last re-mapped address block %x\n",
+				ocmem_read(br_base + BR_LAST_ADDR));
 		complete(&dm_transfer_event);
 	} else if (irq_status & BIT(1)) {
 		pr_debug("Data clear engine completed\n");
-		irq_status &= ~BIT(1);
-		ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+		ocmem_write(BIT(1), dm_base + DM_INTR_CLR);
 		complete(&dm_clear_event);
 	} else {
 		BUG_ON(1);
@@ -259,6 +260,7 @@
 	pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
 
 	wait_for_completion(&dm_transfer_event);
+	pr_debug("Completed transferring %d segments\n", num_chunks);
 	ocmem_disable_core_clock();
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index c380c54..38813e1 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -45,6 +45,7 @@
 	OP_COMPLETE = 0x0,
 	OP_RESCHED,
 	OP_PARTIAL,
+	OP_EVICT,
 	OP_FAIL = ~0x0,
 };
 
@@ -74,7 +75,8 @@
  * hardware state changes can occur. The value will be tweaked on actual
  * hardware.
 */
-#define SCHED_DELAY 10
+/* Delay in ms for switching to low power mode for OCMEM */
+#define SCHED_DELAY 5000
 
 static struct list_head rdm_queue;
 static struct mutex rdm_mutex;
@@ -128,6 +130,7 @@
 
 static struct rb_root sched_tree;
 static struct mutex sched_mutex;
+static struct mutex allocation_mutex;
 
 /* A region represents a continuous interval in OCMEM address space */
 struct ocmem_region {
@@ -307,6 +310,7 @@
 	INIT_LIST_HEAD(&p->sched_list);
 	init_rwsem(&p->rw_sem);
 	SET_STATE(p, R_FREE);
+	pr_debug("request %p created\n", p);
 	return p;
 }
 
@@ -594,6 +598,16 @@
 	if (rc < 0)
 		goto br_clock_fail;
 
+
+	rc = ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
+							get_mode(req->owner));
+
+	if (rc < 0) {
+		pr_err("ocmem: Failed to secure request %p for %d\n", req,
+				req->owner);
+		goto lock_failed;
+	}
+
 	rc = do_map(req);
 
 	if (rc < 0) {
@@ -602,19 +616,12 @@
 		goto process_map_fail;
 
 	}
-
-	if (ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
-							get_mode(req->owner))) {
-		pr_err("ocmem: Failed to secure request %p for %d\n", req,
-				req->owner);
-		rc = -EINVAL;
-		goto lock_failed;
-	}
-
+	pr_debug("ocmem: Mapped request %p\n", req);
 	return 0;
-lock_failed:
-	do_unmap(req);
+
 process_map_fail:
+	ocmem_unlock(req->owner, phys_to_offset(req->req_start), req->req_sz);
+lock_failed:
 	ocmem_disable_br_clock();
 br_clock_fail:
 	ocmem_disable_iface_clock();
@@ -630,22 +637,24 @@
 {
 	int rc = 0;
 
-	if (ocmem_unlock(req->owner, phys_to_offset(req->req_start),
-							req->req_sz)) {
-		pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
-				req->owner);
-		rc = -EINVAL;
-		goto unlock_failed;
-	}
-
 	rc = do_unmap(req);
 
 	if (rc < 0)
 		goto process_unmap_fail;
 
+	rc = ocmem_unlock(req->owner, phys_to_offset(req->req_start),
+						req->req_sz);
+
+	if (rc < 0) {
+		pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
+				req->owner);
+		goto unlock_failed;
+	}
+
 	ocmem_disable_br_clock();
 	ocmem_disable_iface_clock();
 	ocmem_disable_core_clock();
+	pr_debug("ocmem: Unmapped request %p\n", req);
 	return 0;
 
 unlock_failed:
@@ -1009,7 +1018,8 @@
 
 	retry = false;
 
-	pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+	pr_debug("ocmem: do_allocate: %s request size %lx\n",
+						get_name(owner), sz);
 
 retry_next_step:
 
@@ -1036,6 +1046,7 @@
 
 		/* update request state */
 		CLEAR_STATE(req, R_FREE);
+		CLEAR_STATE(req, R_PENDING);
 		SET_STATE(req, R_ALLOCATED);
 		SET_STATE(req, R_MUST_MAP);
 		req->op = SCHED_NOP;
@@ -1065,8 +1076,11 @@
 		/* resolve conflicting regions based on priority */
 		if (overlap_r->max_prio < prio) {
 			if (min == max) {
-				pr_err("ocmem: Requires eviction support\n");
-				goto err_not_supported;
+				req->req_start = zone->z_head;
+				req->req_end = zone->z_head + sz - 1;
+				req->req_sz = 0x0;
+				req->edata = NULL;
+				goto trigger_eviction;
 			} else {
 			/* Try to allocate atleast >= 'min' immediately */
 				sz -= step;
@@ -1109,6 +1123,11 @@
 
 	return OP_COMPLETE;
 
+trigger_eviction:
+	pr_debug("Trigger eviction of region %p\n", overlap_r);
+	destroy_region(region);
+	return OP_EVICT;
+
 err_not_supported:
 	pr_err("ocmem: Scheduled unsupported operation\n");
 	return OP_FAIL;
@@ -1219,12 +1238,9 @@
 	if (rc < 0)
 		return -EINVAL;
 
-	/* Map the newly grown region */
-	if (is_tcm(req->owner)) {
-		rc = process_map(req, req->req_start, req->req_end);
-		if (rc < 0)
-			return -EINVAL;
-	}
+	rc = process_map(req, req->req_start, req->req_end);
+	if (rc < 0)
+		return -EINVAL;
 
 	offset = phys_to_offset(req->req_start);
 
@@ -1281,8 +1297,23 @@
 
 static int ocmem_schedule_pending(void)
 {
-	schedule_delayed_work(&ocmem_sched_thread,
-				msecs_to_jiffies(SCHED_DELAY));
+
+	bool need_sched = false;
+	int i = 0;
+
+	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+		if (!list_empty(&sched_queue[i])) {
+			need_sched = true;
+			break;
+		}
+	}
+
+	if (need_sched == true) {
+		cancel_delayed_work(&ocmem_sched_thread);
+		schedule_delayed_work(&ocmem_sched_thread,
+					msecs_to_jiffies(SCHED_DELAY));
+		pr_debug("ocmem: Scheduled delayed work\n");
+	}
 	return 0;
 }
 
@@ -1298,6 +1329,8 @@
 		goto err_free_fail;
 	}
 
+	pr_debug("ocmem: do_free: client %s req %p\n", get_name(req->owner),
+					req);
 	/* Grab the sched mutex */
 	mutex_lock(&sched_mutex);
 	rc = __sched_free(req);
@@ -1346,10 +1379,15 @@
 		return -EINVAL;
 	}
 
-	if (is_tcm(req->owner)) {
+	if (!TEST_STATE(req, R_FREE)) {
+
 		rc = process_unmap(req, req->req_start, req->req_end);
 		if (rc < 0)
 			return -EINVAL;
+
+		rc = do_free(req);
+		if (rc < 0)
+			return -EINVAL;
 	}
 
 	if (req->req_sz != 0) {
@@ -1365,10 +1403,6 @@
 
 	}
 
-	rc = do_free(req);
-	if (rc < 0)
-		return -EINVAL;
-
 	inc_ocmem_stat(zone_of(req), NR_FREES);
 
 	ocmem_destroy_req(req);
@@ -1437,18 +1471,10 @@
 		return -EINVAL;
 
 	if (!is_mapped(req)) {
-		pr_err("Buffer is not already mapped\n");
+		pr_err("Buffer is not currently mapped\n");
 		goto transfer_out_error;
 	}
 
-	rc = process_unmap(req, req->req_start, req->req_end);
-	if (rc < 0) {
-		pr_err("Unmapping the buffer failed\n");
-		goto transfer_out_error;
-	}
-
-	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
-
 	rc = queue_transfer(req, handle, list, TO_DDR);
 
 	if (rc < 0) {
@@ -1457,6 +1483,7 @@
 		goto transfer_out_error;
 	}
 
+	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
 	return 0;
 
 transfer_out_error:
@@ -1474,19 +1501,14 @@
 	if (!req)
 		return -EINVAL;
 
-	if (is_mapped(req)) {
-		pr_err("Buffer is already mapped\n");
+
+	if (!is_mapped(req)) {
+		pr_err("Buffer is not already mapped for transfer\n");
 		goto transfer_in_error;
 	}
 
-	rc = process_map(req, req->req_start, req->req_end);
-	if (rc < 0) {
-		pr_err("Mapping the buffer failed\n");
-		goto transfer_in_error;
-	}
 
 	inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
-
 	rc = queue_transfer(req, handle, list, TO_OCMEM);
 
 	if (rc < 0) {
@@ -1525,13 +1547,21 @@
 
 	edata = req->edata;
 
-	if (is_tcm(req->owner))
-		do_unmap(req);
+	if (!edata) {
+		pr_err("Unable to find eviction data\n");
+		return -EINVAL;
+	}
+
+	pr_debug("Found edata %p in request %p\n", edata, req);
 
 	inc_ocmem_stat(zone_of(req), NR_SHRINKS);
 
 	if (size == 0) {
-		pr_info("req %p being shrunk to zero\n", req);
+		pr_debug("req %p being shrunk to zero\n", req);
+		if (is_mapped(req))
+			rc = process_unmap(req, req->req_start, req->req_end);
+			if (rc < 0)
+				return -EINVAL;
 		rc = do_free(req);
 		if (rc < 0)
 			return -EINVAL;
@@ -1541,9 +1571,12 @@
 			return -EINVAL;
 	}
 
-	edata->pending--;
-	if (edata->pending == 0) {
-		pr_debug("All regions evicted");
+	req->edata = NULL;
+	CLEAR_STATE(req, R_ALLOCATED);
+	SET_STATE(req, R_FREE);
+
+	if (atomic_dec_and_test(&edata->pending)) {
+		pr_debug("ocmem: All conflicting allocations were shrunk\n");
 		complete(&edata->completion);
 	}
 
@@ -1567,82 +1600,313 @@
 	return rc;
 }
 
-int ocmem_eviction_thread(struct work_struct *work)
+static struct ocmem_eviction_data *init_eviction(int id)
 {
+	struct ocmem_eviction_data *edata = NULL;
+	int prio = ocmem_client_table[id].priority;
+
+	edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+
+	if (!edata) {
+		pr_err("ocmem: Could not allocate eviction data\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&edata->victim_list);
+	INIT_LIST_HEAD(&edata->req_list);
+	edata->prio = prio;
+	atomic_set(&edata->pending, 0);
+	return edata;
+}
+
+static void free_eviction(struct ocmem_eviction_data *edata)
+{
+
+	if (!edata)
+		return;
+
+	if (!list_empty(&edata->req_list))
+		pr_err("ocmem: Eviction data %p not empty\n", edata);
+
+	kfree(edata);
+	edata = NULL;
+}
+
+static bool is_overlapping(struct ocmem_req *new, struct ocmem_req *old)
+{
+
+	if (!new || !old)
+		return false;
+
+	pr_debug("check overlap [%lx -- %lx] on [%lx -- %lx]\n",
+			new->req_start, new->req_end,
+			old->req_start, old->req_end);
+
+	if ((new->req_start < old->req_start &&
+		new->req_end >= old->req_start) ||
+		(new->req_start >= old->req_start &&
+		 new->req_start <= old->req_end &&
+		 new->req_end >= old->req_end)) {
+		pr_debug("request %p overlaps with existing req %p\n",
+						new, old);
+		return true;
+	}
+	return false;
+}
+
+static int __evict_common(struct ocmem_eviction_data *edata,
+						struct ocmem_req *req)
+{
+	struct rb_node *rb_node = NULL;
+	struct ocmem_req *e_req = NULL;
+	bool needs_eviction = false;
+	int j = 0;
+
+	for (rb_node = rb_first(&sched_tree); rb_node;
+			rb_node = rb_next(rb_node)) {
+
+		struct ocmem_region *tmp_region = NULL;
+
+		tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+		if (tmp_region->max_prio < edata->prio) {
+			for (j = edata->prio - 1; j > NO_PRIO; j--) {
+				needs_eviction = false;
+				e_req = find_req_match(j, tmp_region);
+				if (!e_req)
+					continue;
+				if (edata->passive == true) {
+					needs_eviction = true;
+				} else {
+					needs_eviction = is_overlapping(req,
+								e_req);
+				}
+
+				if (needs_eviction) {
+					pr_debug("adding %p in region %p to eviction list\n",
+							e_req, tmp_region);
+					list_add_tail(
+						&e_req->eviction_list,
+						&edata->req_list);
+					atomic_inc(&edata->pending);
+					e_req->edata = edata;
+				}
+			}
+		} else {
+			pr_debug("Skipped region %p\n", tmp_region);
+		}
+	}
+
+	pr_debug("%d requests will be evicted\n", atomic_read(&edata->pending));
+
+	if (!atomic_read(&edata->pending))
+		return -EINVAL;
 	return 0;
 }
 
+static void trigger_eviction(struct ocmem_eviction_data *edata)
+{
+	struct ocmem_req *req = NULL;
+	struct ocmem_req *next = NULL;
+	struct ocmem_buf buffer;
+
+	if (!edata)
+		return;
+
+	BUG_ON(atomic_read(&edata->pending) == 0);
+
+	init_completion(&edata->completion);
+
+	list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+	{
+		if (req) {
+			pr_debug("ocmem: Evicting request %p\n", req);
+			buffer.addr = req->req_start;
+			buffer.len = 0x0;
+			dispatch_notification(req->owner, OCMEM_ALLOC_SHRINK,
+								&buffer);
+		}
+	}
+	return;
+}
+
 int process_evict(int id)
 {
 	struct ocmem_eviction_data *edata = NULL;
-	int prio = ocmem_client_table[id].priority;
-	struct rb_node *rb_node = NULL;
-	struct ocmem_req *req = NULL;
-	struct ocmem_buf buffer;
-	int j = 0;
+	int rc = 0;
 
-	edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+	edata = init_eviction(id);
 
-	INIT_LIST_HEAD(&edata->victim_list);
-	INIT_LIST_HEAD(&edata->req_list);
-	edata->prio = prio;
-	edata->pending = 0;
-	edata->passive = 1;
-	evictions[id] = edata;
+	if (!edata)
+		return -EINVAL;
+
+	edata->passive = true;
 
 	mutex_lock(&sched_mutex);
 
-	for (rb_node = rb_first(&sched_tree); rb_node;
-				rb_node = rb_next(rb_node)) {
-		struct ocmem_region *tmp_region = NULL;
-		tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
-		if (tmp_region->max_prio < prio) {
-			for (j = id - 1; j > NO_PRIO; j--) {
-				req = find_req_match(j, tmp_region);
-				if (req) {
-					pr_info("adding %p to eviction list\n",
-							tmp_region);
-					list_add_tail(
-						&tmp_region->eviction_list,
-						&edata->victim_list);
-					list_add_tail(
-						&req->eviction_list,
-						&edata->req_list);
-					edata->pending++;
-					req->edata = edata;
-					buffer.addr = req->req_start;
-					buffer.len = 0x0;
-					inc_ocmem_stat(zone_of(req),
-								NR_EVICTIONS);
-					dispatch_notification(req->owner,
-						OCMEM_ALLOC_SHRINK, &buffer);
-				}
-			}
-		} else {
-			pr_info("skipping %p from eviction\n", tmp_region);
+	rc = __evict_common(edata, NULL);
+
+	if (rc < 0)
+		goto skip_eviction;
+
+	trigger_eviction(edata);
+
+	evictions[id] = edata;
+
+	mutex_unlock(&sched_mutex);
+
+	wait_for_completion(&edata->completion);
+
+	return 0;
+
+skip_eviction:
+	evictions[id] = NULL;
+	mutex_unlock(&sched_mutex);
+	return 0;
+}
+
+static int run_evict(struct ocmem_req *req)
+{
+	struct ocmem_eviction_data *edata = NULL;
+	int rc = 0;
+
+	if (!req)
+		return -EINVAL;
+
+	edata = init_eviction(req->owner);
+
+	if (!edata)
+		return -EINVAL;
+
+	edata->passive = false;
+
+	rc = __evict_common(edata, req);
+
+	if (rc < 0)
+		goto skip_eviction;
+
+	trigger_eviction(edata);
+
+	pr_debug("ocmem: attaching eviction %p to request %p", edata, req);
+	req->edata = edata;
+
+	wait_for_completion(&edata->completion);
+
+	pr_debug("ocmem: eviction completed successfully\n");
+	return 0;
+
+skip_eviction:
+	pr_err("ocmem: Unable to run eviction\n");
+	free_eviction(edata);
+	return -EINVAL;
+}
+
+static int __restore_common(struct ocmem_eviction_data *edata)
+{
+
+	struct ocmem_req *req = NULL;
+	struct ocmem_req *next = NULL;
+
+	if (!edata)
+		return -EINVAL;
+
+	list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+	{
+		if (req) {
+			pr_debug("ocmem: restoring evicted request %p\n",
+								req);
+			list_del(&req->eviction_list);
+			req->op = SCHED_ALLOCATE;
+			sched_enqueue(req);
+			inc_ocmem_stat(zone_of(req), NR_RESTORES);
 		}
 	}
-	mutex_unlock(&sched_mutex);
-	pr_debug("Waiting for all regions to be shrunk\n");
-	if (edata->pending > 0) {
-		init_completion(&edata->completion);
-		wait_for_completion(&edata->completion);
+
+	pr_debug("Scheduled all evicted regions\n");
+
+	return 0;
+}
+
+static int sched_restore(struct ocmem_req *req)
+{
+
+	int rc = 0;
+
+	if (!req)
+		return -EINVAL;
+
+	if (!req->edata)
+		return 0;
+
+	rc = __restore_common(req->edata);
+
+	if (rc < 0)
+		return -EINVAL;
+
+	free_eviction(req->edata);
+	return 0;
+}
+
+int process_restore(int id)
+{
+	struct ocmem_eviction_data *edata = evictions[id];
+	int rc = 0;
+
+	if (!edata)
+		return -EINVAL;
+
+	rc = __restore_common(edata);
+
+	if (rc < 0) {
+		pr_err("Failed to restore evicted requests\n");
+		return -EINVAL;
 	}
+
+	free_eviction(edata);
+	evictions[id] = NULL;
+	ocmem_schedule_pending();
 	return 0;
 }
 
 static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
 {
 	int rc = 0;
+	int ret = 0;
 	struct ocmem_buf *buffer = req->buffer;
 
 	down_write(&req->rw_sem);
 
+	mutex_lock(&allocation_mutex);
+retry_allocate:
+
 	/* Take the scheduler mutex */
 	mutex_lock(&sched_mutex);
 	rc = __sched_allocate(req, can_block, can_wait);
 	mutex_unlock(&sched_mutex);
 
+	if (rc == OP_EVICT) {
+
+		ret = run_evict(req);
+
+		if (ret == 0) {
+			rc = sched_restore(req);
+			if (rc < 0) {
+				pr_err("Failed to restore for req %p\n", req);
+				goto err_allocate_fail;
+			}
+			req->edata = NULL;
+
+			pr_debug("Attempting to re-allocate req %p\n", req);
+			req->req_start = 0x0;
+			req->req_end = 0x0;
+			goto retry_allocate;
+		} else {
+			goto err_allocate_fail;
+		}
+	}
+
+	mutex_unlock(&allocation_mutex);
+
 	if (rc == OP_FAIL) {
 		inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
 		goto err_allocate_fail;
@@ -1667,6 +1931,7 @@
 	up_write(&req->rw_sem);
 	return 0;
 err_allocate_fail:
+	mutex_unlock(&allocation_mutex);
 	up_write(&req->rw_sem);
 	return -EINVAL;
 }
@@ -1699,33 +1964,6 @@
 	return -EINVAL;
 }
 
-int process_restore(int id)
-{
-	struct ocmem_req *req = NULL;
-	struct ocmem_req *next = NULL;
-	struct ocmem_eviction_data *edata = evictions[id];
-
-	if (!edata)
-		return 0;
-
-	list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
-	{
-		if (req) {
-			pr_debug("ocmem: Fetched evicted request %p\n",
-								req);
-			list_del(&req->sched_list);
-			req->op = SCHED_ALLOCATE;
-			sched_enqueue(req);
-			inc_ocmem_stat(zone_of(req), NR_RESTORES);
-		}
-	}
-	kfree(edata);
-	evictions[id] = NULL;
-	pr_debug("Restore all evicted regions\n");
-	ocmem_schedule_pending();
-	return 0;
-}
-
 int process_allocate(int id, struct ocmem_handle *handle,
 			unsigned long min, unsigned long max,
 			unsigned long step, bool can_block, bool can_wait)
@@ -1774,13 +2012,11 @@
 
 	handle->req = req;
 
-	if (is_tcm(id)) {
+	if (req->req_sz != 0) {
+
 		rc = process_map(req, req->req_start, req->req_end);
 		if (rc < 0)
 			goto map_error;
-	}
-
-	if (req->req_sz != 0) {
 
 		offset = phys_to_offset(req->req_start);
 
@@ -1795,6 +2031,7 @@
 	return 0;
 
 power_ctl_error:
+	process_unmap(req, req->req_start, req->req_end);
 map_error:
 	handle->req = NULL;
 	do_free(req);
@@ -1819,15 +2056,18 @@
 	if (rc < 0)
 		goto do_allocate_error;
 
+	/* The request can still be pending */
+	if (TEST_STATE(req, R_PENDING))
+		return 0;
+
 	inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
 
-	if (is_tcm(id)) {
+	if (req->req_sz != 0) {
+
 		rc = process_map(req, req->req_start, req->req_end);
 		if (rc < 0)
 			goto map_error;
-	}
 
-	if (req->req_sz != 0) {
 
 		offset = phys_to_offset(req->req_start);
 
@@ -1849,6 +2089,7 @@
 	return 0;
 
 power_ctl_error:
+	process_unmap(req, req->req_start, req->req_end);
 map_error:
 	handle->req = NULL;
 	do_free(req);
@@ -1965,6 +2206,7 @@
 
 	sched_tree = RB_ROOT;
 	pdata = platform_get_drvdata(pdev);
+	mutex_init(&allocation_mutex);
 	mutex_init(&sched_mutex);
 	mutex_init(&sched_queue_mutex);
 	ocmem_vaddr = pdata->vbase;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 3ca2163..62085f6 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -272,6 +272,7 @@
 
 	/* 9625 IDs */
 	[134] = MSM_CPU_9625,
+	[152] = MSM_CPU_9625,
 
 	/* 8960AB IDs */
 	[138] = MSM_CPU_8960AB,
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 77922e2..48ce577 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -426,6 +426,10 @@
 			stats.aec.buff = stats.buffer;
 			stats.aec.fd = stats.fd;
 			break;
+		case MSG_ID_STATS_BE:
+			stats.be.buff = stats.buffer;
+			stats.be.fd = stats.fd;
+			break;
 		case MSG_ID_STATS_AF:
 		case MSG_ID_STATS_BF:
 			stats.af.buff = stats.buffer;
@@ -514,6 +518,7 @@
 	CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
 	switch (cfgcmd.cmd_type) {
 	case CMD_STATS_BG_ENABLE:
+	case CMD_STATS_BE_ENABLE:
 	case CMD_STATS_BF_ENABLE:
 	case CMD_STATS_BHIST_ENABLE:
 	case CMD_STATS_AF_ENABLE:
@@ -611,6 +616,8 @@
 			cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
 		else if (buf.type == STAT_BG)
 			cfgcmd.cmd_type = CMD_STATS_BG_BUF_RELEASE;
+		else if (buf.type == STAT_BE)
+			cfgcmd.cmd_type = CMD_STATS_BE_BUF_RELEASE;
 		else if (buf.type == STAT_BF)
 			cfgcmd.cmd_type = CMD_STATS_BF_BUF_RELEASE;
 		else if (buf.type == STAT_BHIST)
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 1875df2..e131193 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -210,6 +210,7 @@
 	case MSM_PMEM_SKIN:
 	case MSM_PMEM_AEC_AWB:
 	case MSM_PMEM_BAYER_GRID:
+	case MSM_PMEM_BAYER_EXPOSURE:
 	case MSM_PMEM_BAYER_FOCUS:
 	case MSM_PMEM_BAYER_HIST:
 		rc = msm_pmem_table_add(ptype, pinfo, client, domain_num);
@@ -241,6 +242,7 @@
 	case MSM_PMEM_SKIN:
 	case MSM_PMEM_AEC_AWB:
 	case MSM_PMEM_BAYER_GRID:
+	case MSM_PMEM_BAYER_EXPOSURE:
 	case MSM_PMEM_BAYER_FOCUS:
 	case MSM_PMEM_BAYER_HIST:
 		hlist_for_each_entry_safe(region, node, n,
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 6091a0d..287c77c 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -254,6 +254,8 @@
 		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
 	[161] = {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
 		V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
+	[163] = {VFE_CMD_STATS_BE_START, V40_STATS_BE_LEN, V40_STATS_BE_OFF},
+	[164] = {VFE_CMD_STATS_BE_STOP},
 };
 
 static const uint32_t vfe40_AXI_WM_CFG[] = {
@@ -818,29 +820,34 @@
 	CDBG("%s: Use bayer stats = %d\n", __func__,
 		 vfe40_use_bayer_stats(vfe40_ctrl));
 
-	msm_camera_io_w(0x8350001F,
-	vfe40_ctrl->share_ctrl->vfebase +
-			VFE_BUS_STATS_HIST_WR_UB_CFG);
-	msm_camera_io_w(0x8370002F,
-		vfe40_ctrl->share_ctrl->vfebase +
-			VFE_BUS_STATS_BG_WR_UB_CFG);
-	msm_camera_io_w(0x83A0002F,
-		vfe40_ctrl->share_ctrl->vfebase +
-			VFE_BUS_STATS_BF_WR_UB_CFG);
-	msm_camera_io_w(0x83D0000F,
+	msm_camera_io_w(0x82F80007,
 		vfe40_ctrl->share_ctrl->vfebase +
 			VFE_BUS_STATS_RS_WR_UB_CFG);
-	msm_camera_io_w(0x83E00007,
+	msm_camera_io_w(0x8300000F,
 		vfe40_ctrl->share_ctrl->vfebase +
 			VFE_BUS_STATS_CS_WR_UB_CFG);
-	msm_camera_io_w(0x83E80007,
+
+	msm_camera_io_w(0x8310003F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BG_WR_UB_CFG);
+	msm_camera_io_w(0x8350003F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BE_WR_UB_CFG);
+	msm_camera_io_w(0x8390003F,
+		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BF_WR_UB_CFG);
+
+	msm_camera_io_w(0x83D0000F,
+	vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_HIST_WR_UB_CFG);
+	msm_camera_io_w(0x83E0000F,
 		vfe40_ctrl->share_ctrl->vfebase +
 			VFE_BUS_STATS_SKIN_WR_UB_CFG);
+
 	msm_camera_io_w(0x83F0000F,
 		vfe40_ctrl->share_ctrl->vfebase +
 			VFE_BUS_STATS_AWB_WR_UB_CFG);
 
-
 	/* stats frame subsample config*/
 	msm_camera_io_w(0xFFFFFFFF,
 		vfe40_ctrl->share_ctrl->vfebase +
@@ -850,6 +857,9 @@
 			VFE_BUS_STATS_BG_WR_FRAMEDROP_PATTERN);
 	msm_camera_io_w(0xFFFFFFFF,
 		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN);
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase +
 			VFE_BUS_STATS_BF_WR_FRAMEDROP_PATTERN);
 	msm_camera_io_w(0xFFFFFFFF,
 		vfe40_ctrl->share_ctrl->vfebase +
@@ -873,6 +883,9 @@
 			VFE_BUS_STATS_BG_WR_IRQ_SUBSAMPLE_PATTERN);
 	msm_camera_io_w(0xFFFFFFFF,
 		vfe40_ctrl->share_ctrl->vfebase +
+			VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN);
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase +
 			VFE_BUS_STATS_BF_WR_IRQ_SUBSAMPLE_PATTERN);
 	msm_camera_io_w(0xFFFFFFFF,
 		vfe40_ctrl->share_ctrl->vfebase +
@@ -894,13 +907,16 @@
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	/* Stats control variables. */
-	memset(&(vfe40_ctrl->afbfStatsControl), 0,
+	memset(&(vfe40_ctrl->bfStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe40_ctrl->awbStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
-	memset(&(vfe40_ctrl->aecbgStatsControl), 0,
+	memset(&(vfe40_ctrl->bgStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->beStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe40_ctrl->bhistStatsControl), 0,
@@ -1086,7 +1102,6 @@
 {
 	uint32_t addr;
 	unsigned long flags;
-
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
 	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
@@ -1111,7 +1126,40 @@
 	return 0;
 }
 
-static uint32_t vfe_stats_aec_bg_buf_init(
+static uint32_t vfe_stats_be_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t addr;
+	unsigned long flags;
+	uint32_t stats_type;
+
+	stats_type = MSM_STATS_TYPE_BE;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq BE ping buf from free buf queue\n",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_BE_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq BE pong buf from free buf queue\n",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_BE_WR_PONG_ADDR);
+	return 0;
+}
+
+static uint32_t vfe_stats_bg_buf_init(
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
@@ -1144,7 +1192,7 @@
 	return 0;
 }
 
-static int vfe_stats_af_bf_buf_init(
+static int vfe_stats_bf_buf_init(
 	struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	uint32_t addr;
@@ -1189,7 +1237,6 @@
 {
 	uint32_t addr;
 	unsigned long flags;
-
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
 	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
@@ -1856,7 +1903,7 @@
 			rc = -EFAULT;
 			goto proc_general_done;
 		}
-		rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+		rc = vfe_stats_bg_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AEC",
 				 __func__);
@@ -1890,7 +1937,7 @@
 			rc = -EFAULT;
 			goto proc_general_done;
 		}
-		rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+		rc = vfe_stats_bf_buf_init(vfe40_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AF",
 				__func__);
@@ -2030,15 +2077,25 @@
 		break;
 
 	case VFE_CMD_STATS_BG_START:
+	case VFE_CMD_STATS_BE_START:
 	case VFE_CMD_STATS_BF_START:
 	case VFE_CMD_STATS_BHIST_START: {
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
 		module_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
-		if (VFE_CMD_STATS_BG_START == cmd->id) {
+
+		if (VFE_CMD_STATS_BE_START == cmd->id) {
+			module_val |= BE_ENABLE_MASK;
+			rc = vfe_stats_be_buf_init(vfe40_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of BG",
+					__func__);
+				goto proc_general_done;
+			}
+		} else if (VFE_CMD_STATS_BG_START == cmd->id) {
 			module_val |= BG_ENABLE_MASK;
-			rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+			rc = vfe_stats_bg_buf_init(vfe40_ctrl);
 			if (rc < 0) {
 				pr_err("%s: cannot config ping/pong address of BG",
 					__func__);
@@ -2046,7 +2103,7 @@
 			}
 		} else if (VFE_CMD_STATS_BF_START == cmd->id) {
 			module_val |= BF_ENABLE_MASK;
-			rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+			rc = vfe_stats_bf_buf_init(vfe40_ctrl);
 			if (rc < 0) {
 				pr_err("%s: cannot config ping/pong address of BF",
 					__func__);
@@ -2679,11 +2736,6 @@
 		break;
 
 	case VFE_CMD_STATS_AWB_STOP: {
-		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
-			/* Error */
-			rc = -EFAULT;
-			goto proc_general_done;
-		}
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~AWB_ENABLE_MASK;
@@ -2691,29 +2743,36 @@
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
-	case VFE_CMD_STATS_AE_STOP: {
-		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
-			/* Error */
-			rc = -EFAULT;
-			goto proc_general_done;
-		}
+	case VFE_CMD_STATS_BG_STOP: {
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
-		old_val &= BG_ENABLE_MASK;
+		old_val &= ~BG_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
-	case VFE_CMD_STATS_AF_STOP: {
-		if (vfe40_use_bayer_stats(vfe40_ctrl)) {
-			/* Error */
-			rc = -EFAULT;
-			goto proc_general_done;
-		}
+	case VFE_CMD_STATS_BF_STOP: {
 		old_val = msm_camera_io_r(
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+
+		rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
+				MSM_STATS_TYPE_BF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				   __func__, rc);
+			return -EINVAL;
+			}
+		}
+		break;
+
+	case VFE_CMD_STATS_BE_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~BE_ENABLE_MASK;
+		msm_camera_io_w(old_val,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
@@ -2745,8 +2804,6 @@
 		}
 		break;
 
-	case VFE_CMD_STATS_BG_STOP:
-	case VFE_CMD_STATS_BF_STOP:
 	case VFE_CMD_STATS_BHIST_STOP: {
 		if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
 			/* Error */
@@ -2761,15 +2818,6 @@
 
 		msm_camera_io_w(old_val,
 			vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
-		if (VFE_CMD_STATS_BF_STOP == cmd->id) {
-			rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
-					MSM_STATS_TYPE_BF);
-			if (rc < 0) {
-				pr_err("%s: dq stats buf err = %d",
-					   __func__, rc);
-				return -EINVAL;
-			}
-		}
 		}
 		break;
 
@@ -4015,6 +4063,16 @@
 				vfe40_ctrl->stats_ops.client);
 		}
 		break;
+	case statsBeNum:{
+		msgStats.id = MSG_ID_STATS_BE;
+		stats_type = MSM_STATS_TYPE_BE;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				stats_type, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
 	case statsBfNum:{
 		msgStats.id = MSG_ID_STATS_BF;
 		stats_type =  MSM_STATS_TYPE_BF;
@@ -4101,9 +4159,9 @@
 
 	msgStats.status_bits = status_bits;
 
-	msgStats.aec.buff = vfe40_ctrl->aecbgStatsControl.bufToRender;
+	msgStats.aec.buff = vfe40_ctrl->bgStatsControl.bufToRender;
 	msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
-	msgStats.af.buff = vfe40_ctrl->afbfStatsControl.bufToRender;
+	msgStats.af.buff = vfe40_ctrl->bfStatsControl.bufToRender;
 
 	msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
 	msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
@@ -4118,6 +4176,29 @@
 				&msgStats);
 }
 
+static void vfe40_process_stats_be_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	uint32_t stats_type;
+	stats_type = MSM_STATS_TYPE_BE;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->beStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsBeNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->beStatsControl.bufToRender, statsBeNum);
+	} else{
+		vfe40_ctrl->beStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->beStatsControl.droppedStatsFrameCount);
+	}
+}
+
 static void vfe40_process_stats_bg_irq(struct vfe40_ctrl_type *vfe40_ctrl)
 {
 	unsigned long flags;
@@ -4128,16 +4209,16 @@
 	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (addr) {
-		vfe40_ctrl->aecbgStatsControl.bufToRender =
+		vfe40_ctrl->bgStatsControl.bufToRender =
 			vfe40_process_stats_irq_common(vfe40_ctrl, statsBgNum,
 			addr);
 
 		vfe_send_stats_msg(vfe40_ctrl,
-			vfe40_ctrl->aecbgStatsControl.bufToRender, statsBgNum);
+			vfe40_ctrl->bgStatsControl.bufToRender, statsBgNum);
 	} else{
-		vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+		vfe40_ctrl->bgStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
-			vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount);
+			vfe40_ctrl->bgStatsControl.droppedStatsFrameCount);
 	}
 }
 
@@ -4172,16 +4253,16 @@
 	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
 	if (addr) {
-		vfe40_ctrl->afbfStatsControl.bufToRender =
+		vfe40_ctrl->bfStatsControl.bufToRender =
 			vfe40_process_stats_irq_common(vfe40_ctrl, statsBfNum,
 			addr);
 
 		vfe_send_stats_msg(vfe40_ctrl,
-			vfe40_ctrl->afbfStatsControl.bufToRender, statsBfNum);
+			vfe40_ctrl->bfStatsControl.bufToRender, statsBfNum);
 	} else{
-		vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+		vfe40_ctrl->bfStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
-			vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount);
+			vfe40_ctrl->bfStatsControl.droppedStatsFrameCount);
 	}
 }
 
@@ -4282,22 +4363,39 @@
 
 	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
 	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
-	stats_type = MSM_STATS_TYPE_BG;
 
+	stats_type = MSM_STATS_TYPE_BE;
+	if (status_bits & VFE_IRQ_STATUS0_STATS_BE) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+				stats_type);
+		if (addr) {
+			vfe40_ctrl->beStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsBeNum, addr);
+			process_stats = true;
+		} else{
+			vfe40_ctrl->beStatsControl.bufToRender = 0;
+			vfe40_ctrl->beStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe40_ctrl->beStatsControl.bufToRender = 0;
+	}
+
+	stats_type = MSM_STATS_TYPE_BG;
 	if (status_bits & VFE_IRQ_STATUS0_STATS_BG) {
 		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
 				stats_type);
 		if (addr) {
-			vfe40_ctrl->aecbgStatsControl.bufToRender =
+			vfe40_ctrl->bgStatsControl.bufToRender =
 				vfe40_process_stats_irq_common(
 				vfe40_ctrl, statsBgNum, addr);
 			process_stats = true;
 		} else{
-			vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
-			vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+			vfe40_ctrl->bgStatsControl.bufToRender = 0;
+			vfe40_ctrl->bgStatsControl.droppedStatsFrameCount++;
 		}
 	} else {
-		vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+		vfe40_ctrl->bgStatsControl.bufToRender = 0;
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
@@ -4322,17 +4420,17 @@
 		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
 					stats_type);
 		if (addr) {
-			vfe40_ctrl->afbfStatsControl.bufToRender =
+			vfe40_ctrl->bfStatsControl.bufToRender =
 				vfe40_process_stats_irq_common(
 				vfe40_ctrl, statsBfNum,
 				addr);
 			process_stats = true;
 		} else {
-			vfe40_ctrl->afbfStatsControl.bufToRender = 0;
-			vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+			vfe40_ctrl->bfStatsControl.bufToRender = 0;
+			vfe40_ctrl->bfStatsControl.droppedStatsFrameCount++;
 		}
 	} else {
-		vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+		vfe40_ctrl->bfStatsControl.bufToRender = 0;
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
@@ -4441,6 +4539,10 @@
 		CDBG("Stats BG irq occured.\n");
 		vfe40_process_stats_bg_irq(vfe40_ctrl);
 		break;
+	case VFE_IRQ_STATUS0_STATS_BE:
+		CDBG("Stats BE irq occured.\n");
+		vfe40_process_stats_be_irq(vfe40_ctrl);
+		break;
 	case VFE_IRQ_STATUS0_STATS_BF:
 		CDBG("Stats BF irq occured.\n");
 		vfe40_process_stats_bf_irq(vfe40_ctrl);
@@ -4522,6 +4624,8 @@
 				(qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_BG) |
 				(qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_BE) |
+				(qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_AWB) |
 				(qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_BF) |
@@ -4610,6 +4714,12 @@
 					(void *)VFE_IRQ_STATUS0_STATS_BG);
 
 				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_BE)
+					v4l2_subdev_notify(&vfe40_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_BE);
+
+				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AWB)
 					v4l2_subdev_notify(&vfe40_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
@@ -4879,6 +4989,7 @@
 		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BE_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
 		cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
@@ -4922,6 +5033,7 @@
 		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)   ||
 		(cmd->cmd_type == CMD_STATS_BG_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BE_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_BF_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
 		struct axidata *axid;
@@ -4945,6 +5057,7 @@
 		switch (cmd->cmd_type) {
 		case CMD_STATS_AEC_ENABLE:
 		case CMD_STATS_BG_ENABLE:
+		case CMD_STATS_BE_ENABLE:
 		case CMD_STATS_BF_ENABLE:
 		case CMD_STATS_BHIST_ENABLE:
 		case CMD_STATS_AWB_ENABLE:
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 6363bfb..4acc7e4 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -796,7 +796,7 @@
 #define VFE_BUS_STATS_BE_WR_PING_ADDR    0x00000168
 #define VFE_BUS_STATS_BE_WR_PONG_ADDR    0x0000016C
 #define VFE_BUS_STATS_BE_WR_ADDR_CFG    0x00000170
-#define VFE_BUS_STATS_BE_UB_CFG          0x00000174
+#define VFE_BUS_STATS_BE_WR_UB_CFG          0x00000174
 #define VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN  0x00000178
 #define VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN 0x0000017C
 
@@ -1014,9 +1014,10 @@
 	uint32_t sync_timer_number;
 
 	struct msm_ver_num_info ver_num;
-	struct vfe_stats_control afbfStatsControl;
+	struct vfe_stats_control beStatsControl;
+	struct vfe_stats_control bfStatsControl;
 	struct vfe_stats_control awbStatsControl;
-	struct vfe_stats_control aecbgStatsControl;
+	struct vfe_stats_control bgStatsControl;
 	struct vfe_stats_control ihistStatsControl;
 	struct vfe_stats_control rsStatsControl;
 	struct vfe_stats_control csStatsControl;
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index e1a0994..7d44fea 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -442,12 +442,13 @@
 struct buffer_info {
 	struct list_head list;
 	int type;
-	int fd;
-	int buff_off;
-	int size;
-	u32 uvaddr;
-	u32 device_addr;
-	struct msm_smem *handle;
+	int num_planes;
+	int fd[VIDEO_MAX_PLANES];
+	int buff_off[VIDEO_MAX_PLANES];
+	int size[VIDEO_MAX_PLANES];
+	u32 uvaddr[VIDEO_MAX_PLANES];
+	u32 device_addr[VIDEO_MAX_PLANES];
+	struct msm_smem *handle[VIDEO_MAX_PLANES];
 };
 
 struct msm_v4l2_vid_inst {
@@ -472,26 +473,37 @@
 }
 
 struct buffer_info *get_registered_buf(struct list_head *list,
-				int fd, u32 buff_off, u32 size)
+				int fd, u32 buff_off, u32 size, int *plane)
 {
 	struct buffer_info *temp;
 	struct buffer_info *ret = NULL;
-	if (!list || fd < 0) {
+	int i;
+	if (!list || fd < 0 || !plane) {
 		dprintk(VIDC_ERR, "Invalid input\n");
 		goto err_invalid_input;
 	}
+	*plane = 0;
 	if (!list_empty(list)) {
 		list_for_each_entry(temp, list, list) {
-			if (temp && temp->fd == fd &&
-			(CONTAINS(temp->buff_off, temp->size, buff_off)
-			|| CONTAINS(buff_off, size, temp->buff_off)
-			|| OVERLAPS(buff_off, size,
-				temp->buff_off, temp->size))) {
-				dprintk(VIDC_INFO,
-				"This memory region is already mapped\n");
-				ret = temp;
-				break;
+			for (i = 0; (i < temp->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				if (temp && temp->fd[i] == fd &&
+						(CONTAINS(temp->buff_off[i],
+						temp->size[i], buff_off)
+						 || CONTAINS(buff_off,
+						 size, temp->buff_off[i])
+						 || OVERLAPS(buff_off, size,
+						 temp->buff_off[i],
+						 temp->size[i]))) {
+					dprintk(VIDC_DBG,
+							"This memory region is already mapped\n");
+					ret = temp;
+					*plane = i;
+					break;
+				}
 			}
+			if (ret)
+				break;
 		}
 	}
 err_invalid_input:
@@ -499,25 +511,62 @@
 }
 
 struct buffer_info *get_same_fd_buffer(struct list_head *list,
-		int fd)
+		int fd, int *plane)
 {
 	struct buffer_info *temp;
 	struct buffer_info *ret = NULL;
-	if (!list || fd < 0) {
+	int i;
+	if (!list || fd < 0 || !plane) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		goto err_invalid_input;
+	}
+	*plane = 0;
+	if (!list_empty(list)) {
+		list_for_each_entry(temp, list, list) {
+			for (i = 0; (i < temp->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				if (temp && temp->fd[i] == fd)  {
+					dprintk(VIDC_INFO,
+					"Found same fd buffer\n");
+					ret = temp;
+					*plane = i;
+					break;
+				}
+			}
+			if (ret)
+				break;
+		}
+	}
+err_invalid_input:
+	return ret;
+}
+static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+{
+	struct buffer_info *temp;
+	u32 uvaddr = 0;
+	int i;
+	if (!list || !device_addr) {
 		dprintk(VIDC_ERR, "Invalid input\n");
 		goto err_invalid_input;
 	}
 	if (!list_empty(list)) {
 		list_for_each_entry(temp, list, list) {
-			if (temp && temp->fd == fd)  {
-				dprintk(VIDC_INFO, "Found same fd buffer\n");
-				ret = temp;
-				break;
+			for (i = 0; (i < temp->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				if (temp && temp->device_addr[i]
+						== device_addr)  {
+					dprintk(VIDC_INFO,
+					"Found same fd buffer\n");
+					uvaddr = temp->uvaddr[i];
+					break;
+				}
 			}
+			if (uvaddr)
+				break;
 		}
 	}
 err_invalid_input:
-	return ret;
+	return uvaddr;
 }
 
 static int msm_v4l2_open(struct file *filp)
@@ -567,23 +616,27 @@
 	struct list_head *ptr, *next;
 	struct buffer_info *bi;
 	struct v4l2_buffer buffer_info;
-	struct v4l2_plane plane;
+	struct v4l2_plane plane[VIDEO_MAX_PLANES];
 	int rc = 0;
+	int i;
 	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
 		bi = list_entry(ptr, struct buffer_info, list);
 		if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 			buffer_info.type = bi->type;
-			plane.reserved[0] = bi->fd;
-			plane.reserved[1] = bi->buff_off;
-			plane.length = bi->size;
-			plane.m.userptr = bi->device_addr;
-			buffer_info.m.planes = &plane;
-			buffer_info.length = 1;
-			dprintk(VIDC_DBG,
-				"Releasing buffer: %d, %d, %d\n",
-				buffer_info.m.planes[0].reserved[0],
-				buffer_info.m.planes[0].reserved[1],
-				buffer_info.m.planes[0].length);
+			for (i = 0; (i < bi->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				plane[i].reserved[0] = bi->fd[i];
+				plane[i].reserved[1] = bi->buff_off[i];
+				plane[i].length = bi->size[i];
+				plane[i].m.userptr = bi->device_addr[i];
+				buffer_info.m.planes = plane;
+				dprintk(VIDC_DBG,
+					"Releasing buffer: %d, %d, %d\n",
+					buffer_info.m.planes[i].reserved[0],
+					buffer_info.m.planes[i].reserved[1],
+					buffer_info.m.planes[i].length);
+			}
+			buffer_info.length = bi->num_planes;
 			rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
 					&buffer_info);
 			if (rc)
@@ -593,11 +646,13 @@
 					buffer_info.m.planes[0].reserved[1],
 					buffer_info.m.planes[0].length);
 			list_del(&bi->list);
-			if (bi->handle)
-				msm_smem_free(v4l2_inst->mem_client,
-					bi->handle);
-			kfree(bi);
+			for (i = 0; i < bi->num_planes; i++) {
+				if (bi->handle[i])
+					msm_smem_free(v4l2_inst->mem_client,
+							bi->handle[i]);
 			}
+			kfree(bi);
+		}
 	}
 	return rc;
 }
@@ -609,6 +664,7 @@
 	struct buffer_info *bi;
 	struct msm_vidc_inst *vidc_inst;
 	struct msm_v4l2_vid_inst *v4l2_inst;
+	int i;
 	vidc_inst = get_vidc_inst(filp, NULL);
 	v4l2_inst = get_v4l2_inst(filp, NULL);
 	rc = msm_v4l2_release_output_buffers(v4l2_inst);
@@ -620,9 +676,12 @@
 		bi = list_entry(ptr, struct buffer_info, list);
 		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 			list_del(&bi->list);
-			if (bi->handle)
-				msm_smem_free(v4l2_inst->mem_client,
-					bi->handle);
+			for (i = 0; (i < bi->num_planes)
+				&& (i < VIDEO_MAX_PLANES); i++) {
+				if (bi->handle[i])
+					msm_smem_free(v4l2_inst->mem_client,
+							bi->handle[i]);
+			}
 			kfree(bi);
 		}
 	}
@@ -696,6 +755,7 @@
 	struct buffer_info *temp;
 	struct msm_vidc_inst *vidc_inst;
 	struct msm_v4l2_vid_inst *v4l2_inst;
+	int plane = 0;
 	int i, rc = 0;
 	vidc_inst = get_vidc_inst(file, fh);
 	v4l2_inst = get_v4l2_inst(file, fh);
@@ -704,34 +764,41 @@
 		rc = -ENOMEM;
 		goto exit;
 	}
+	binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+	if (!binfo) {
+		dprintk(VIDC_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+			b->length, VIDEO_MAX_PLANES);
+		rc = -EINVAL;
+		goto exit;
+	}
 	for (i = 0; i < b->length; ++i) {
-		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+		temp = get_registered_buf(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0],
 				b->m.planes[i].reserved[1],
-				b->m.planes[i].length);
-		if (binfo) {
-			dprintk(VIDC_INFO,
+				b->m.planes[i].length, &plane);
+		if (temp) {
+			dprintk(VIDC_DBG,
 				"This memory region has already been prepared\n");
 			rc = -EINVAL;
-			goto exit;
-		}
-		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-		if (!binfo) {
-			dprintk(VIDC_ERR, "Out of memory\n");
-			rc = -ENOMEM;
+			kfree(binfo);
 			goto exit;
 		}
 		temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
-				b->m.planes[i].reserved[0]);
+				b->m.planes[i].reserved[0], &plane);
 		if (temp) {
 			binfo->type = b->type;
-			binfo->fd = b->m.planes[i].reserved[0];
-			binfo->buff_off = b->m.planes[i].reserved[1];
-			binfo->size = b->m.planes[i].length;
-			binfo->uvaddr = b->m.planes[i].m.userptr;
-			binfo->device_addr =
-				temp->handle->device_addr + binfo->buff_off;
-			binfo->handle = NULL;
+			binfo->fd[i] = b->m.planes[i].reserved[0];
+			binfo->buff_off[i] = b->m.planes[i].reserved[1];
+			binfo->size[i] = b->m.planes[i].length;
+			binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+			binfo->device_addr[i] =
+			temp->handle[plane]->device_addr + binfo->buff_off[i];
+			binfo->handle[i] = NULL;
 		} else {
 			handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
 			b->m.planes[i].reserved[0],
@@ -745,21 +812,22 @@
 				goto exit;
 			}
 			binfo->type = b->type;
-			binfo->fd = b->m.planes[i].reserved[0];
-			binfo->buff_off = b->m.planes[i].reserved[1];
-			binfo->size = b->m.planes[i].length;
-			binfo->uvaddr = b->m.planes[i].m.userptr;
-			binfo->device_addr =
-				handle->device_addr + binfo->buff_off;
-			binfo->handle = handle;
+			binfo->fd[i] = b->m.planes[i].reserved[0];
+			binfo->buff_off[i] = b->m.planes[i].reserved[1];
+			binfo->size[i] = b->m.planes[i].length;
+			binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+			binfo->device_addr[i] =
+				handle->device_addr + binfo->buff_off[i];
+			binfo->handle[i] = handle;
 			dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
 					b->m.planes[i].reserved[0],
 					b->m.planes[i].reserved[1],
 					b->m.planes[i].length);
 		}
-		list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
-		b->m.planes[i].m.userptr = binfo->device_addr;
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
 	}
+	binfo->num_planes = b->length;
+	list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
 	rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
 exit:
 	return rc;
@@ -771,15 +839,21 @@
 	struct msm_vidc_inst *vidc_inst;
 	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct buffer_info *binfo;
+	int plane = 0;
 	int rc = 0;
 	int i;
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
+			b->length);
+		return -EINVAL;
+	}
 	vidc_inst = get_vidc_inst(file, fh);
 	v4l2_inst = get_v4l2_inst(file, fh);
 	for (i = 0; i < b->length; ++i) {
 		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0],
 				b->m.planes[i].reserved[1],
-				b->m.planes[i].length);
+				b->m.planes[i].length, &plane);
 		if (!binfo) {
 			dprintk(VIDC_ERR,
 				"This buffer is not registered: %d, %d, %d\n",
@@ -789,12 +863,12 @@
 			rc = -EINVAL;
 			goto err_invalid_buff;
 		}
-		b->m.planes[i].m.userptr = binfo->device_addr;
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
 		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
-				binfo->device_addr);
-		if (binfo->handle) {
+				binfo->device_addr[i]);
+		if (binfo->handle[i]) {
 			rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
-					binfo->handle);
+					binfo->handle[i]);
 			if (rc) {
 				dprintk(VIDC_ERR,
 					"Failed to clean caches: %d\n", rc);
@@ -810,8 +884,37 @@
 int msm_v4l2_dqbuf(struct file *file, void *fh,
 				struct v4l2_buffer *b)
 {
+	int rc = 0;
+	int i;
+	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
-	return msm_vidc_dqbuf((void *)vidc_inst, b);
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
+			b->length);
+		return -EINVAL;
+	}
+	v4l2_inst = get_v4l2_inst(file, fh);
+	rc = msm_vidc_dqbuf((void *)vidc_inst, b);
+	if (rc) {
+		dprintk(VIDC_DBG,
+			"Failed to dqbuf, capability: %d, rc: %d\n",
+			b->type, rc);
+		goto fail_dq_buf;
+	}
+	for (i = 0; i < b->length; i++) {
+		b->m.planes[i].m.userptr = device_to_uvaddr(
+				&v4l2_inst->registered_bufs,
+				b->m.planes[i].m.userptr);
+		if (!b->m.planes[i].m.userptr) {
+			dprintk(VIDC_ERR,
+			"Failed to find user virtual address, 0x%lx, %d, %d\n",
+			b->m.planes[i].m.userptr, b->type, i);
+			rc = -EINVAL;
+			goto fail_dq_buf;
+		}
+	}
+fail_dq_buf:
+	return rc;
 }
 
 int msm_v4l2_streamon(struct file *file, void *fh,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index bd9cfb2..058c835 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -20,7 +20,6 @@
 #include "msm_vidc_debug.h"
 
 #define MSM_VDEC_DVC_NAME "msm_vdec_8974"
-#define MAX_PLANES 1
 #define DEFAULT_HEIGHT 720
 #define DEFAULT_WIDTH 1280
 #define MAX_SUPPORTED_WIDTH 1920
@@ -186,11 +185,6 @@
 	size = ALIGN(size, SZ_4K);
 	return size;
 }
-static u32 get_frame_size_nv21(int plane,
-					u32 height, u32 width)
-{
-	return height * width * 2;
-}
 
 static u32 get_frame_size_compressed(int plane,
 					u32 height, u32 width)
@@ -203,7 +197,7 @@
 		.name = "YCbCr Semiplanar 4:2:0",
 		.description = "Y/CbCr 4:2:0",
 		.fourcc = V4L2_PIX_FMT_NV12,
-		.num_planes = 1,
+		.num_planes = 2,
 		.get_frame_size = get_frame_size_nv12,
 		.type = CAPTURE_PORT,
 	},
@@ -264,14 +258,6 @@
 		.type = OUTPUT_PORT,
 	},
 	{
-		.name = "YCrCb Semiplanar 4:2:0",
-		.description = "Y/CrCb 4:2:0",
-		.fourcc = V4L2_PIX_FMT_NV21,
-		.num_planes = 1,
-		.get_frame_size = get_frame_size_nv21,
-		.type = CAPTURE_PORT,
-	},
-	{
 		.name = "DIVX 311",
 		.description = "DIVX 311 compressed format",
 		.fourcc = V4L2_PIX_FMT_DIVX_311,
@@ -332,45 +318,48 @@
 					struct v4l2_buffer *b)
 {
 	int rc = 0;
-	int i;
 	struct vidc_buffer_addr_info buffer_info;
+	int extra_idx = 0;
+	int i;
 	switch (b->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		for (i = 0; i < b->length; i++) {
-			dprintk(VIDC_DBG, "device_addr = %ld, size = %d\n",
-				b->m.planes[i].m.userptr,
+			if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+				dprintk(VIDC_ERR,
+				"Planes mismatch: needed: %d, allocated: %d\n",
+				inst->fmts[CAPTURE_PORT]->num_planes,
+				b->length);
+				rc = -EINVAL;
+				break;
+			}
+			for (i = 0; (i < b->length)
+				&& (i < VIDEO_MAX_PLANES); ++i) {
+				dprintk(VIDC_DBG,
+				"prepare plane: %d, device_addr = 0x%lx, size = %d\n",
+				i, b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
-			buffer_info.buffer_size = b->m.planes[i].length;
+			}
+			buffer_info.buffer_size = b->m.planes[0].length;
 			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
-				b->m.planes[i].m.userptr;
-			if (!inst->extradata_handle) {
-				inst->extradata_handle =
-				msm_smem_alloc(inst->mem_client,
-				4096 * 1024, 1, SMEM_UNCACHED,
-				inst->core->resources.io_map[NS_MAP].domain,
-				0, 0);
-				if (!inst->extradata_handle) {
-					dprintk(VIDC_ERR,
-						"Failed to allocate extradata memory\n");
-					rc = -ENOMEM;
-					break;
-				}
+				b->m.planes[0].m.userptr;
+			extra_idx = EXTRADATA_IDX(b->length);
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+				buffer_info.extradata_addr =
+					b->m.planes[extra_idx].m.userptr;
+				dprintk(VIDC_DBG,
+				"extradata: 0x%lx\n",
+				b->m.planes[extra_idx].m.userptr);
+				buffer_info.extradata_size =
+					b->m.planes[extra_idx].length;
 			}
-			buffer_info.extradata_addr =
-				inst->extradata_handle->device_addr;
-			buffer_info.extradata_size = 4096 * 1024;
 			rc = vidc_hal_session_set_buffers((void *)inst->session,
 					&buffer_info);
-			if (rc) {
+			if (rc)
 				dprintk(VIDC_ERR,
-					"vidc_hal_session_set_buffers failed\n");
-				break;
-			}
-		}
+				"vidc_hal_session_set_buffers failed");
 		break;
 	default:
 		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
@@ -383,9 +372,10 @@
 					struct v4l2_buffer *b)
 {
 	int rc = 0;
-	int i;
 	struct vidc_buffer_addr_info buffer_info;
 	struct msm_vidc_core *core = inst->core;
+	int extra_idx = 0;
+	int i;
 	if (inst->state == MSM_VIDC_CORE_INVALID ||
 			core->state == VIDC_CORE_INVALID) {
 		dprintk(VIDC_ERR,
@@ -393,28 +383,40 @@
 				core);
 		goto exit;
 	}
+
 	switch (b->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		for (i = 0; i < b->length; i++) {
-			dprintk(VIDC_DBG,
-				"Release device_addr = %ld, size = %d\n",
-				b->m.planes[i].m.userptr,
+			if (b->length !=
+				inst->fmts[CAPTURE_PORT]->num_planes) {
+				dprintk(VIDC_ERR,
+				"Planes mismatch: needed: %d, to release: %d\n",
+				inst->fmts[CAPTURE_PORT]->num_planes,
+				b->length);
+				rc = -EINVAL;
+				break;
+			}
+			for (i = 0; i < b->length; ++i) {
+				dprintk(VIDC_DBG,
+				"Release plane: %d device_addr = 0x%lx, size = %d\n",
+				i, b->m.planes[i].m.userptr,
 				b->m.planes[i].length);
-			buffer_info.buffer_size = b->m.planes[i].length;
+			}
+			buffer_info.buffer_size = b->m.planes[0].length;
 			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
-				 b->m.planes[i].m.userptr;
-			buffer_info.extradata_addr =
-				inst->extradata_handle->device_addr;
+				 b->m.planes[0].m.userptr;
+			extra_idx = EXTRADATA_IDX(b->length);
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+				buffer_info.extradata_addr =
+					b->m.planes[extra_idx].m.userptr;
 			rc = vidc_hal_session_release_buffers(
 					(void *)inst->session, &buffer_info);
 			if (rc)
 				dprintk(VIDC_ERR,
-					"vidc_hal_session_release_buffers failed\n");
-		}
+				"vidc_hal_session_release_buffers failed");
 		break;
 	default:
 		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
@@ -486,7 +488,10 @@
 int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 {
 	const struct msm_vidc_format *fmt = NULL;
+	struct hal_frame_size frame_sz;
+	int extra_idx = 0;
 	int rc = 0;
+	int ret;
 	int i;
 	if (!inst || !f) {
 		dprintk(VIDC_ERR,
@@ -500,21 +505,41 @@
 
 	if (fmt) {
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		if (inst->in_reconfig == true) {
 			inst->prop.height = inst->reconfig_height;
 			inst->prop.width = inst->reconfig_width;
 		}
 		f->fmt.pix_mp.height = inst->prop.height;
 		f->fmt.pix_mp.width = inst->prop.width;
-		f->fmt.pix_mp.num_planes = fmt->num_planes;
-		for (i = 0; i < fmt->num_planes; ++i) {
-			f->fmt.pix_mp.plane_fmt[i].sizeimage =
-			fmt->get_frame_size(i, inst->prop.height,
-				inst->prop.width);
+		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+		frame_sz.width = inst->prop.width;
+		frame_sz.height = inst->prop.height;
+		dprintk(VIDC_DBG, "width = %d, height = %d\n",
+				frame_sz.width, frame_sz.height);
+		ret = msm_comm_try_set_prop(inst,
+			HAL_PARAM_FRAME_SIZE, &frame_sz);
+		ret = ret || msm_comm_try_get_bufreqs(inst);
+		if (ret || (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+			for (i = 0; i < fmt->num_planes; ++i) {
+				f->fmt.pix_mp.plane_fmt[i].sizeimage =
+					fmt->get_frame_size(i,
+						f->fmt.pix_mp.height,
+						f->fmt.pix_mp.width);
+			}
+		} else {
+			f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+			extra_idx = EXTRADATA_IDX(fmt->num_planes);
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+				f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+			}
 		}
 	} else {
-		dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
-					f->type);
+		dprintk(VIDC_ERR,
+			"Buf type not recognized, type = %d\n",
+			f->type);
 		rc = -EINVAL;
 	}
 	return rc;
@@ -523,7 +548,10 @@
 int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 {
 	const struct msm_vidc_format *fmt = NULL;
+	struct hal_frame_size frame_sz;
+	int extra_idx = 0;
 	int rc = 0;
+	int ret = 0;
 	int i;
 	if (!inst || !f) {
 		dprintk(VIDC_ERR,
@@ -536,64 +564,67 @@
 		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
 			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
 			CAPTURE_PORT);
-		if (fmt && fmt->type != CAPTURE_PORT) {
+		if (!fmt || (fmt && fmt->type != CAPTURE_PORT)) {
 			dprintk(VIDC_ERR,
-				"Format: %d not supported on CAPTURE"
-				"port\n", f->fmt.pix_mp.pixelformat);
-			rc = -EINVAL;
-			goto err_invalid_fmt;
-		}
-
-		inst->prop.width = f->fmt.pix_mp.width;
-		inst->prop.height = f->fmt.pix_mp.height;
-
-		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
-		frame_sz.width = inst->prop.width;
-		frame_sz.height = inst->prop.height;
-		dprintk(VIDC_DBG,
-			"width = %d, height = %d\n",
-			frame_sz.width, frame_sz.height);
-		rc = vidc_hal_session_set_property((void *)inst->session,
-				HAL_PARAM_FRAME_SIZE, &frame_sz);
-		if (rc) {
-			dprintk(VIDC_ERR,
-				"Failed to set hal property for framesize\n");
-			goto err_invalid_fmt;
-		}
-	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		inst->prop.width = f->fmt.pix_mp.width;
-		inst->prop.height = f->fmt.pix_mp.height;
-		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
-			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
-			OUTPUT_PORT);
-		if (fmt && fmt->type != OUTPUT_PORT) {
-			dprintk(VIDC_ERR,
-				"Format: %d not supported on OUTPUT port\n",
+				"Format: %d not supported on CAPTURE port\n",
 				f->fmt.pix_mp.pixelformat);
 			rc = -EINVAL;
 			goto err_invalid_fmt;
 		}
-	}
-
-	if (fmt) {
-		f->fmt.pix_mp.num_planes = fmt->num_planes;
-		for (i = 0; i < fmt->num_planes; ++i) {
-			f->fmt.pix_mp.plane_fmt[i].sizeimage =
-				fmt->get_frame_size(i, f->fmt.pix_mp.height,
-						f->fmt.pix_mp.width);
-		}
 		inst->fmts[fmt->type] = fmt;
-		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-			rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
-			if (rc) {
-				dprintk(VIDC_ERR, "Failed to open instance\n");
-				goto err_invalid_fmt;
+		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+		frame_sz.width = inst->prop.width;
+		frame_sz.height = inst->prop.height;
+		dprintk(VIDC_DBG, "width = %d, height = %d\n",
+				frame_sz.width, frame_sz.height);
+		ret = msm_comm_try_set_prop(inst,
+			HAL_PARAM_FRAME_SIZE, &frame_sz);
+		ret = ret || msm_comm_try_get_bufreqs(inst);
+		if (ret) {
+			for (i = 0; i < fmt->num_planes; ++i) {
+				f->fmt.pix_mp.plane_fmt[i].sizeimage =
+					fmt->get_frame_size(i,
+						f->fmt.pix_mp.height,
+						f->fmt.pix_mp.width);
+			}
+		} else {
+			f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+			extra_idx = EXTRADATA_IDX(fmt->num_planes);
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+				f->fmt.pix_mp.plane_fmt[1].sizeimage =
+		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
 			}
 		}
-	} else {
-		dprintk(VIDC_ERR,
-			"Buf type not recognized, type = %d\n", f->type);
-		rc = -EINVAL;
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		inst->prop.width = f->fmt.pix_mp.width;
+		inst->prop.height = f->fmt.pix_mp.height;
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+				ARRAY_SIZE(vdec_formats),
+				f->fmt.pix_mp.pixelformat,
+				OUTPUT_PORT);
+		if (!fmt || fmt->type != OUTPUT_PORT) {
+			dprintk(VIDC_ERR,
+			"Format: %d not supported on OUTPUT port\n",
+			f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+		inst->fmts[fmt->type] = fmt;
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			goto err_invalid_fmt;
+		}
+		frame_sz.buffer_type = HAL_BUFFER_INPUT;
+		frame_sz.width = inst->prop.width;
+		frame_sz.height = inst->prop.height;
+		msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			fmt->get_frame_size(0, f->fmt.pix_mp.height,
+					f->fmt.pix_mp.width);
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
 	}
 err_invalid_fmt:
 	return rc;
@@ -657,14 +688,17 @@
 	struct msm_vidc_inst *inst;
 	unsigned long flags;
 	struct hal_buffer_requirements *bufreq;
-	if (!q || !q->drv_priv) {
-		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+	int extra_idx = 0;
+	if (!q || !num_buffers || !num_planes
+		|| !sizes || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
+			q, num_buffers, num_planes);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		*num_planes = 1;
+		*num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
 		if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
 				*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
 			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
@@ -675,6 +709,7 @@
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
+		*num_planes = inst->fmts[CAPTURE_PORT]->num_planes;
 		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to open instance\n");
@@ -686,7 +721,6 @@
 				"Failed to get buffer requirements: %d\n", rc);
 			break;
 		}
-		*num_planes = 1;
 		spin_lock_irqsave(&inst->lock, flags);
 		if (*num_buffers && *num_buffers >
 			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
@@ -711,11 +745,13 @@
 				inst->buff_req.buffer[1].buffer_count_actual,
 				inst->buff_req.buffer[1].buffer_size,
 				inst->buff_req.buffer[1].buffer_alignment);
-		for (i = 0; i < *num_planes; i++) {
-			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
-					i, inst->prop.height, inst->prop.width);
+		sizes[0] = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			sizes[extra_idx] =
+		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
 		}
-
 		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index ed234b9..54c3d5f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -685,7 +685,7 @@
 	struct vb2_buffer *vb;
 	struct vidc_hal_fbd *fill_buf_done;
 	if (!response) {
-		pr_err("Invalid response from vidc_hal\n");
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
 		return;
 	}
 	inst = (struct msm_vidc_inst *)response->session_id;
@@ -1545,14 +1545,14 @@
 			dprintk(VIDC_DBG, "Sent etb to HAL\n");
 		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 			struct vidc_seq_hdr seq_hdr;
+			int extra_idx = 0;
 			frame_data.filled_len = 0;
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
-			if (inst->extradata_handle) {
+			extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+			if (extra_idx)
 				frame_data.extradata_addr =
-					inst->extradata_handle->device_addr;
-			} else {
-				frame_data.extradata_addr = 0;
-			}
+					vb->v4l2_planes[extra_idx].m.userptr;
 			dprintk(VIDC_DBG,
 				"Sending ftb to hal: Alloc: %d :filled: %d",
 				frame_data.alloc_len, frame_data.filled_len);
@@ -1596,6 +1596,12 @@
 {
 	int rc = 0;
 	mutex_lock(&inst->sync_lock);
+	if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+		dprintk(VIDC_ERR,
+			"Not in proper state to query buffer requirements\n");
+		rc = -EAGAIN;
+		goto exit;
+	}
 	init_completion(
 		&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
 	rc = vidc_hal_session_get_buf_req((void *) inst->session);
@@ -1721,6 +1727,29 @@
 	return rc;
 }
 
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input: %p\n", inst);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->sync_lock);
+	if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+		dprintk(VIDC_ERR, "Not in proper state to set property\n");
+		rc = -EAGAIN;
+		goto exit;
+	}
+	rc = vidc_hal_session_set_property((void *)inst->session,
+			ptype, pdata);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
+exit:
+	mutex_unlock(&inst->sync_lock);
+	return rc;
+}
+
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 20b4bc2..7562058 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -27,6 +27,8 @@
 		struct msm_vidc_inst *inst, enum v4l2_buf_type type);
 int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
 int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, void *pdata);
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
 int msm_comm_qbuf(struct vb2_buffer *vb);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 0f6740f..f288cc6 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -74,6 +74,8 @@
 	uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
 	buf_size = y_buf_size + uv_buf_size; }
 
+#define EXTRADATA_IDX(__num_planes) (__num_planes - 1)
+
 enum vidc_ports {
 	OUTPUT_PORT,
 	CAPTURE_PORT,
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index fef3dd5..d3fa1d0 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -359,7 +359,7 @@
 	HAL_BUFFER_EXTRADATA_OUTPUT2,
 	HAL_BUFFER_INTERNAL_SCRATCH,
 	HAL_BUFFER_INTERNAL_PERSIST,
-	HAL_UNUSED_BUFFER = 0x10000000,
+	HAL_BUFFER_MAX
 };
 
 struct hal_frame_rate {
@@ -942,7 +942,7 @@
 };
 
 struct buffer_requirements {
-	struct hal_buffer_requirements buffer[8];
+	struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
 };
 
 /* VIDC_HAL CORE API's */
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 103c1a3..53e965c 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -218,6 +218,8 @@
 	if (ret < 0) {
 		dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
 			ret);
+		dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
+		disable_irq_nosync(wcd9xxx->irq);
 		wcd9xxx_unlock_sleep(wcd9xxx);
 		return IRQ_NONE;
 	}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ca5f890..b711fd9 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -81,6 +81,42 @@
 			 unsigned long arg);
 static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 
+void mdss_fb_no_update_notify_timer_cb(unsigned long data)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
+	if (!mfd)
+		pr_err("%s mfd NULL\n", __func__);
+	complete(&mfd->no_update.comp);
+}
+
+static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
+							unsigned long *argp)
+{
+	int ret, notify;
+
+	ret = copy_from_user(&notify, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s:ioctl failed\n", __func__);
+		return ret;
+	}
+
+	if (notify > NOTIFY_UPDATE_STOP)
+		return -EINVAL;
+
+	if (notify == NOTIFY_UPDATE_START) {
+		INIT_COMPLETION(mfd->update.comp);
+		ret = wait_for_completion_interruptible_timeout(
+						&mfd->update.comp, 4 * HZ);
+	} else {
+		INIT_COMPLETION(mfd->no_update.comp);
+		ret = wait_for_completion_interruptible_timeout(
+						&mfd->no_update.comp, 4 * HZ);
+	}
+	if (ret == 0)
+		ret = -ETIMEDOUT;
+	return (ret > 0) ? 0 : ret;
+}
+
 #define MAX_BACKLIGHT_BRIGHTNESS 255
 static int lcd_backlight_registered;
 
@@ -101,7 +137,9 @@
 	if (!bl_lvl && value)
 		bl_lvl = 1;
 
+	mutex_lock(&mfd->lock);
 	mdss_fb_set_backlight(mfd, bl_lvl);
+	mutex_unlock(&mfd->lock);
 }
 
 static struct led_classdev backlight_led = {
@@ -209,6 +247,8 @@
 	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
 	mfd->panel_info.frame_count = 0;
 	mfd->bl_level = 0;
+	mfd->bl_scale = 1024;
+	mfd->bl_min_lvl = 30;
 	mfd->fb_imgType = MDP_RGBA_8888;
 
 	mfd->pdev = pdev;
@@ -269,6 +309,11 @@
 		pr_err("msm_fb_remove: can't stop the device %d\n",
 			    mfd->index);
 
+	if (mfd->no_update.timer.function)
+		del_timer(&mfd->no_update.timer);
+	complete(&mfd->no_update.comp);
+	complete(&mfd->update.comp);
+
 	/* remove /dev/fb* */
 	unregister_framebuffer(mfd->fbi);
 
@@ -416,9 +461,46 @@
 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;
+	pr_debug("input = %d, scale = %d", temp, mfd->bl_scale);
+	if (temp >= mfd->bl_min_lvl) {
+		/* bl_scale is the numerator of scaling fraction (x/1024)*/
+		temp = (temp * mfd->bl_scale) / 1024;
+
+		/*if less than minimum level, use min level*/
+		if (temp < mfd->bl_min_lvl)
+			temp = mfd->bl_min_lvl;
+	}
+	pr_debug("output = %d", temp);
+
+	(*bl_lvl) = temp;
+}
+
+/* must call this function from within mfd->lock */
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
 {
 	struct mdss_panel_data *pdata;
+	u32 temp = bkl_lvl;
 
 	if (!mfd->panel_power_on || !bl_updated) {
 		unset_bl_level = bkl_lvl;
@@ -430,15 +512,22 @@
 	pdata = dev_get_platdata(&mfd->pdev->dev);
 
 	if ((pdata) && (pdata->set_backlight)) {
-		mutex_lock(&mfd->lock);
-		if (bl_level_old == bkl_lvl) {
-			mutex_unlock(&mfd->lock);
+		mdss_fb_scale_bl(mfd, &temp);
+		/*
+		 * Even though backlight has been scaled, want to show that
+		 * backlight has been set to bkl_lvl to those that read from
+		 * sysfs node. Thus, need to set bl_level even if it appears
+		 * the backlight has already been set to the level it is at,
+		 * as well as setting bl_level to bkl_lvl even though the
+		 * backlight has been set to the scaled value.
+		 */
+		if (bl_level_old == temp) {
+			mfd->bl_level = bkl_lvl;
 			return;
 		}
+		pdata->set_backlight(pdata, temp);
 		mfd->bl_level = bkl_lvl;
-		pdata->set_backlight(pdata, mfd->bl_level);
-		bl_level_old = mfd->bl_level;
-		mutex_unlock(&mfd->lock);
+		bl_level_old = temp;
 	}
 }
 
@@ -822,6 +911,13 @@
 
 	mfd->op_enable = true;
 
+	mutex_init(&mfd->no_update.lock);
+	init_timer(&mfd->no_update.timer);
+	mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
+	mfd->no_update.timer.data = (unsigned long)mfd;
+	init_completion(&mfd->update.comp);
+	init_completion(&mfd->no_update.comp);
+
 	if (mfd->lut_update) {
 		ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 		if (ret)
@@ -1124,7 +1220,8 @@
 	return 0;
 }
 
-static int mdss_fb_handle_pp_ioctl(void __user *argp)
+static int mdss_fb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
+							void __user *argp)
 {
 	int ret;
 	struct msmfb_mdp_pp mdp_pp;
@@ -1179,6 +1276,10 @@
 		ret = mdss_mdp_gamut_config(&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;
@@ -1256,7 +1357,11 @@
 		break;
 
 	case MSMFB_MDP_PP:
-		ret = mdss_fb_handle_pp_ioctl(argp);
+		ret = mdss_fb_handle_pp_ioctl(mfd, argp);
+		break;
+
+	case MSMFB_NOTIFY_UPDATE:
+		ret = mdss_fb_notify_update(mfd, argp);
 		break;
 
 	default:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 25c39f6..78f2b9a 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -41,6 +41,13 @@
 	int panel_power_on;
 };
 
+struct disp_info_notify {
+	int type;
+	struct timer_list timer;
+	struct completion comp;
+	struct mutex lock;
+};
+
 struct msm_fb_data_type {
 	u32 key;
 	u32 index;
@@ -83,6 +90,8 @@
 	unsigned long cursor_buf_iova;
 
 	u32 bl_level;
+	u32 bl_scale;
+	u32 bl_min_lvl;
 	struct mutex lock;
 
 	struct platform_device *pdev;
@@ -98,6 +107,8 @@
 	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;
 };
 
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 452ebdc..d52df66 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -406,6 +406,15 @@
 	if (IS_ERR_VALUE(ret))
 		return ret;
 
+	complete(&mfd->update.comp);
+	mutex_lock(&mfd->no_update.lock);
+	if (mfd->no_update.timer.function)
+		del_timer(&(mfd->no_update.timer));
+
+	mfd->no_update.timer.expires = jiffies + (2 * HZ);
+	add_timer(&mfd->no_update.timer);
+	mutex_unlock(&mfd->no_update.lock);
+
 	mutex_lock(&mfd->lock);
 	list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
 		list_del(&pipe->cleanup_list);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6e04124..e4be407 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -99,6 +99,7 @@
 	u32 hist_cnt_read;
 	u32 hist_cnt_sent;
 	u32 frame_cnt;
+	u32 is_kick_ready;
 	struct completion comp;
 	u32 data[HIST_V_SIZE];
 };
@@ -365,6 +366,7 @@
 	struct pp_hist_col_info *hist_info;
 	struct pp_sts_type *pp_sts;
 	u32 data, tbl_idx, col_state;
+	unsigned long flag;
 	int i;
 	dspp_num = mixer->num;
 	/* no corresponding dspp */
@@ -377,20 +379,19 @@
 		/* HIST_EN & AUTO_CLEAR */
 		opmode |= (1 << 16) | (1 << 17);
 		mutex_lock(&mdss_mdp_hist_mutex);
-		if (hist_info->col_state == HIST_READY)
-			pp_hist_read(base + MDSS_MDP_REG_DSPP_HIST_CTL_BASE +
-				0x1C, hist_info);
-		spin_lock(&mdss_hist_lock);
+		spin_lock_irqsave(&mdss_hist_lock, flag);
 		col_state = hist_info->col_state;
-		if ((col_state == HIST_IDLE) ||
-			(col_state == HIST_READY) ||
-			(col_state == HIST_START)) {
+		if (hist_info->is_kick_ready &&
+				((col_state == HIST_IDLE) ||
+				((false == hist_info->read_request) &&
+						col_state == HIST_READY))) {
 			/* Kick off collection */
 			MDSS_MDP_REG_WRITE(base +
 				MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
 			hist_info->col_state = HIST_START;
 		}
-		spin_unlock(&mdss_hist_lock);
+		hist_info->is_kick_ready = true;
+		spin_unlock_irqrestore(&mdss_hist_lock, flag);
 		mutex_unlock(&mdss_mdp_hist_mutex);
 	}
 
@@ -1263,6 +1264,7 @@
 	int i, ret = 0;
 	u32 disp_num, dspp_num = 0;
 	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	unsigned long flag;
 
 	if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(req->block >= MDP_BLOCK_MAX))
@@ -1296,7 +1298,7 @@
 				__func__, dspp_num);
 			goto hist_start_exit;
 		}
-		spin_lock(&mdss_hist_lock);
+		spin_lock_irqsave(&mdss_hist_lock, flag);
 		hist_info->frame_cnt = req->frame_cnt;
 		init_completion(&hist_info->comp);
 		hist_info->hist_cnt_read = 0;
@@ -1304,7 +1306,8 @@
 		hist_info->read_request = false;
 		hist_info->col_state = HIST_RESET;
 		hist_info->col_en = true;
-		spin_unlock(&mdss_hist_lock);
+		hist_info->is_kick_ready = false;
+		spin_unlock_irqrestore(&mdss_hist_lock, flag);
 		mdss_pp_res->hist_col[disp_num][i] =
 			&mdss_pp_res->dspp_hist[dspp_num];
 		mdss_mdp_hist_irq_enable(3 << done_shift_bit);
@@ -1329,6 +1332,7 @@
 	u32 dspp_num, disp_num, ctl_base, done_bit;
 	struct pp_hist_col_info *hist_info;
 	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	unsigned long flag;
 
 	if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(block >= MDP_BLOCK_MAX))
@@ -1362,10 +1366,11 @@
 			goto hist_stop_exit;
 		}
 		complete_all(&hist_info->comp);
-		spin_lock(&mdss_hist_lock);
+		spin_lock_irqsave(&mdss_hist_lock, flag);
 		hist_info->col_en = false;
 		hist_info->col_state = HIST_UNKNOWN;
-		spin_unlock(&mdss_hist_lock);
+		hist_info->is_kick_ready = false;
+		spin_unlock_irqrestore(&mdss_hist_lock, flag);
 		mdss_mdp_hist_irq_disable(done_bit);
 		MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
 	}
@@ -1386,6 +1391,7 @@
 	struct pp_hist_col_info *hist_info;
 	u32 dspp_num, disp_num, ctl_base;
 	u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+	unsigned long flag;
 
 	if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(hist->block >= MDP_BLOCK_MAX))
@@ -1418,55 +1424,50 @@
 			ret = -EINVAL;
 			goto hist_collect_exit;
 		}
-		spin_lock(&mdss_hist_lock);
-		if ((hist_info->col_state == HIST_READY) ||
-			(hist_info->hist_cnt_read == 0)) {
-			/* wait for hist done if cache has no data */
-			if ((hist_info->col_state != HIST_READY) &&
-				(hist_info->hist_cnt_read == 0)) {
-				hist_info->read_request = true;
-				spin_unlock(&mdss_hist_lock);
-				timeout = HIST_WAIT_TIMEOUT *
-					hist_info->frame_cnt;
-				mutex_unlock(&mdss_mdp_hist_mutex);
-				wait_ret = wait_for_completion_killable_timeout(
+		spin_lock_irqsave(&mdss_hist_lock, flag);
+		/* wait for hist done if cache has no data */
+		if (hist_info->col_state != HIST_READY) {
+			hist_info->read_request = true;
+			spin_unlock_irqrestore(&mdss_hist_lock, flag);
+			timeout = HIST_WAIT_TIMEOUT *
+				hist_info->frame_cnt;
+			mutex_unlock(&mdss_mdp_hist_mutex);
+			wait_ret = wait_for_completion_killable_timeout(
 					&(hist_info->comp), timeout);
 
-				mutex_lock(&mdss_mdp_hist_mutex);
-				hist_info->read_request = false;
-				if (wait_ret == 0) {
-					ret = -ETIMEDOUT;
-					pr_debug("%s: bin collection timedout",
+			mutex_lock(&mdss_mdp_hist_mutex);
+			if (wait_ret == 0) {
+				ret = -ETIMEDOUT;
+				pr_debug("%s: bin collection timedout",
 						__func__);
-					goto hist_collect_exit;
-				} else if (wait_ret < 0) {
-					ret = -EINTR;
-					pr_debug("%s: bin collection interrupted",
+				goto hist_collect_exit;
+			} else if (wait_ret < 0) {
+				ret = -EINTR;
+				pr_debug("%s: bin collection interrupted",
 						__func__);
-					goto hist_collect_exit;
-				}
-				if (hist_info->col_state != HIST_READY) {
-					ret = -EBUSY;
-					pr_err("%s: collection state is not ready: %d",
-						__func__, hist_info->col_state);
-					goto hist_collect_exit;
-				}
-			} else {
-				spin_unlock(&mdss_hist_lock);
+				goto hist_collect_exit;
 			}
-			if (hist_info->col_state == HIST_READY) {
-				v_base = ctl_base + 0x1C;
-				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-				pp_hist_read(v_base, hist_info);
-				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-				spin_lock(&mdss_hist_lock);
-				hist_info->col_state = HIST_IDLE;
-				spin_unlock(&mdss_hist_lock);
+			if (hist_info->col_state != HIST_READY) {
+				ret = -ENODATA;
+				pr_debug("%s: collection state is not ready: %d",
+						__func__, hist_info->col_state);
+				goto hist_collect_exit;
 			}
 		} else {
-			spin_unlock(&mdss_hist_lock);
+			spin_unlock_irqrestore(&mdss_hist_lock, flag);
 		}
-		hist_info->hist_cnt_sent = hist_info->hist_cnt_read;
+		spin_lock_irqsave(&mdss_hist_lock, flag);
+		if (hist_info->col_state == HIST_READY) {
+			spin_unlock_irqrestore(&mdss_hist_lock, flag);
+			v_base = ctl_base + 0x1C;
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+			pp_hist_read(v_base, hist_info);
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+			spin_lock_irqsave(&mdss_hist_lock, flag);
+			hist_info->read_request = false;
+			hist_info->col_state = HIST_IDLE;
+		}
+		spin_unlock_irqrestore(&mdss_hist_lock, flag);
 	}
 	if (mixer_cnt > 1) {
 		memset(&mdss_pp_res->hist_data[disp_num][0],
@@ -1482,7 +1483,7 @@
 	} else {
 		*hist_data_addr = (u32)hist_info->data;
 	}
-
+	hist_info->hist_cnt_sent++;
 hist_collect_exit:
 	mutex_unlock(&mdss_mdp_hist_mutex);
 	return ret;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 1cdc434..98050ce 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -399,7 +399,7 @@
 	uint32_t block;
 	uint8_t frame_cnt;
 	uint8_t bit_mask;
-	uint8_t num_bins;
+	uint16_t num_bins;
 };
 
 /*
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 6658b8c..9af15e3 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -536,6 +536,8 @@
 #define CMD_STATS_BHIST_BUF_RELEASE 58
 #define CMD_VFE_PIX_SOF_COUNT_UPDATE 59
 #define CMD_VFE_COUNT_PIX_SOF_ENABLE 60
+#define CMD_STATS_BE_ENABLE 61
+#define CMD_STATS_BE_BUF_RELEASE 62
 
 #define CMD_AXI_CFG_PRIM               BIT(8)
 #define CMD_AXI_CFG_PRIM_ALL_CHNLS     BIT(9)
@@ -599,7 +601,8 @@
 #define MSM_PMEM_BAYER_GRID		20
 #define MSM_PMEM_BAYER_FOCUS	21
 #define MSM_PMEM_BAYER_HIST		22
-#define MSM_PMEM_MAX            23
+#define MSM_PMEM_BAYER_EXPOSURE 23
+#define MSM_PMEM_MAX            24
 
 #define STAT_AEAW			0
 #define STAT_AEC			1
@@ -611,8 +614,9 @@
 #define STAT_SKIN			7
 #define STAT_BG				8
 #define STAT_BF				9
-#define STAT_BHIST			10
-#define STAT_MAX			11
+#define STAT_BE				10
+#define STAT_BHIST			11
+#define STAT_MAX			12
 
 #define FRAME_PREVIEW_OUTPUT1		0
 #define FRAME_PREVIEW_OUTPUT2		1
@@ -631,6 +635,7 @@
 	MSM_STATS_TYPE_SKIN,    /* legacy based SKIN */
 	MSM_STATS_TYPE_BG,  /* Bayer Grids */
 	MSM_STATS_TYPE_BF,  /* Bayer Focus */
+	MSM_STATS_TYPE_BE,  /* Bayer Exposure*/
 	MSM_STATS_TYPE_BHIST,   /* Bayer Hist */
 	MSM_STATS_TYPE_AE_AW,   /* legacy stats for vfe 2.x*/
 	MSM_STATS_TYPE_COMP, /* Composite stats */
@@ -807,6 +812,7 @@
 	struct stats_buff aec;
 	struct stats_buff awb;
 	struct stats_buff af;
+	struct stats_buff be;
 	struct stats_buff ihist;
 	struct stats_buff rs;
 	struct stats_buff cs;
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index faaa522..8b4ae19 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -70,6 +70,7 @@
 #define MSG_ID_RDI2_UPDATE_ACK          51
 #define MSG_ID_PIX0_UPDATE_ACK          52
 #define MSG_ID_PREV_STOP_ACK            53
+#define MSG_ID_STATS_BE                 54
 
 
 /* ISP command IDs */
@@ -236,7 +237,8 @@
 #define VFE_CMD_COLORXFORM_ENC_UPDATE                   160
 #define VFE_CMD_COLORXFORM_VIEW_UPDATE                  161
 #define VFE_CMD_TEST_GEN_CFG                            162
-
+#define VFE_CMD_STATS_BE_START                          163
+#define VFE_CMD_STATS_BE_STOP                           164
 struct msm_isp_cmd {
 	int32_t  id;
 	uint16_t length;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 956e4cd..db37b7c 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4467,6 +4467,9 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+	/* TX VHIGH comparator */
+	TAIKO_REG_VAL(TAIKO_A_TX_SUP_SWITCH_CTRL_2, 0x90),
 };
 
 static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 30a0214..653effa 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -68,7 +68,7 @@
 #define FW_READ_ATTEMPTS 15
 #define FW_READ_TIMEOUT 2000000
 
-#define BUTTON_POLLING_SUPPORTED false
+#define BUTTON_POLLING_SUPPORTED true
 
 #define MCLK_RATE_12288KHZ 12288000
 #define MCLK_RATE_9600KHZ 9600000
@@ -564,9 +564,21 @@
 		return;
 	pr_debug("%s: Setting up %s detection\n", __func__,
 		 ins ? "insert" : "removal");
-	/* Enable interrupt and insertion detection */
+	/* Disable detection to avoid glitch */
+	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
+	/* Override mbhc power switch to avoid false IRQs */
+	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_1_MBHC, 1 << 2,
+			    !ins << 2);
+	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_2_MBHC, 1 << 2,
+			    !ins << 2);
+	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_3_MBHC, 1 << 2,
+			    !ins << 2);
+	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_4_MBHC, 1 << 2,
+			    !ins << 2);
 	snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
-		      (0x69 | (ins ? (1 << 1) : 0)));
+		      (0x68 | (ins ? (1 << 1) : 0)));
+	/* Re-enable detection */
+	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
 }
 
 /* called under codec_resource_lock acquisition */