diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index f5ae85d27692..453223dc195a 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -143,6 +143,12 @@ Optional Properties:
 				Specify the name of GPU temperature sensor. This name will be used
 				to get the temperature from the thermal driver API.
 
+- qcom,enable-midframe-timer:
+				Boolean. Enables the use of midframe sampling timer. This timer
+				samples the GPU powerstats if the cmdbatch expiry takes longer than
+				the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if
+				target has NAP state enabled.
+
 GPU Quirks:
 - qcom,gpu-quirk-two-pass-use-wfi:
 				Signal the GPU to set Set TWOPASSUSEWFI bit in
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 18c05e930216..0d068e9c5805 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -604,6 +604,16 @@ static int sendcmd(struct adreno_device *adreno_dev,
 			if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE,
 				&dispatcher->priv))
 				reinit_completion(&dispatcher->idle_gate);
+
+			/*
+			 * We update power stats generally at the expire of
+			 * cmdbatch. In cases where the cmdbatch takes a long
+			 * time to finish, it will delay power stats update,
+			 * in effect it will delay DCVS decision. Start a
+			 * timer to update power state on expire of this timer.
+			 */
+			kgsl_pwrscale_midframe_timer_restart(device);
+
 		} else {
 			kgsl_active_count_put(device);
 			clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 172de7406c26..cd9a82a9bf4a 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2355,6 +2355,7 @@ static int _init(struct kgsl_device *device)
 	case KGSL_STATE_ACTIVE:
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		del_timer_sync(&device->idle_timer);
+		kgsl_pwrscale_midframe_timer_cancel(device);
 		device->ftbl->stop(device);
 		/* fall through */
 	case KGSL_STATE_AWARE:
@@ -2462,6 +2463,7 @@ _aware(struct kgsl_device *device)
 	case KGSL_STATE_ACTIVE:
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		del_timer_sync(&device->idle_timer);
+		kgsl_pwrscale_midframe_timer_cancel(device);
 		break;
 	case KGSL_STATE_SLUMBER:
 		status = kgsl_pwrctrl_enable(device);
@@ -2486,6 +2488,8 @@ _nap(struct kgsl_device *device)
 			return -EBUSY;
 		}
 
+		kgsl_pwrscale_midframe_timer_cancel(device);
+
 		/*
 		 * Read HW busy counters before going to NAP state.
 		 * The data might be used by power scale governors
@@ -2522,6 +2526,7 @@ _slumber(struct kgsl_device *device)
 		/* fall through */
 	case KGSL_STATE_NAP:
 		del_timer_sync(&device->idle_timer);
+		kgsl_pwrscale_midframe_timer_cancel(device);
 		if (device->pwrctrl.thermal_cycle == CYCLE_ACTIVE) {
 			device->pwrctrl.thermal_cycle = CYCLE_ENABLE;
 			del_timer_sync(&device->pwrctrl.thermal_timer);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 85cd29b5364e..413a3098b0ef 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -13,6 +13,7 @@
 
 #include <linux/export.h>
 #include <linux/kernel.h>
+#include <linux/hrtimer.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -37,6 +38,18 @@ static struct kgsl_popp popp_param[POPP_MAX] = {
 	{0, 0},
 };
 
+/**
+* struct kgsl_midframe_info - midframe power stats sampling info
+* @timer - midframe sampling timer
+* @timer_check_ws - Updates powerstats on midframe expiry
+* @device - pointer to kgsl_device
+*/
+static struct kgsl_midframe_info {
+	struct hrtimer timer;
+	struct work_struct timer_check_ws;
+	struct kgsl_device *device;
+} *kgsl_midframe = NULL;
+
 static void do_devfreq_suspend(struct work_struct *work);
 static void do_devfreq_resume(struct work_struct *work);
 static void do_devfreq_notify(struct work_struct *work);
@@ -183,9 +196,57 @@ void kgsl_pwrscale_update(struct kgsl_device *device)
 	if (device->state != KGSL_STATE_SLUMBER)
 		queue_work(device->pwrscale.devfreq_wq,
 			&device->pwrscale.devfreq_notify_ws);
+
+	kgsl_pwrscale_midframe_timer_restart(device);
 }
 EXPORT_SYMBOL(kgsl_pwrscale_update);
 
+void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device)
+{
+	if (kgsl_midframe) {
+		WARN_ON(!mutex_is_locked(&device->mutex));
+
+		/* If the timer is already running, stop it */
+		if (hrtimer_active(&kgsl_midframe->timer))
+			hrtimer_cancel(
+				&kgsl_midframe->timer);
+
+		hrtimer_start(&kgsl_midframe->timer,
+				ns_to_ktime(KGSL_GOVERNOR_CALL_INTERVAL
+					* NSEC_PER_USEC), HRTIMER_MODE_REL);
+	}
+}
+EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_restart);
+
+void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device)
+{
+	if (kgsl_midframe) {
+		WARN_ON(!mutex_is_locked(&device->mutex));
+		hrtimer_cancel(&kgsl_midframe->timer);
+	}
+}
+EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_cancel);
+
+static void kgsl_pwrscale_midframe_timer_check(struct work_struct *work)
+{
+	struct kgsl_device *device = kgsl_midframe->device;
+
+	mutex_lock(&device->mutex);
+	if (device->state == KGSL_STATE_ACTIVE)
+		kgsl_pwrscale_update(device);
+	mutex_unlock(&device->mutex);
+}
+
+static enum hrtimer_restart kgsl_pwrscale_midframe_timer(struct hrtimer *timer)
+{
+	struct kgsl_device *device = kgsl_midframe->device;
+
+	queue_work(device->pwrscale.devfreq_wq,
+			&kgsl_midframe->timer_check_ws);
+
+	return HRTIMER_NORESTART;
+}
+
 /*
  * kgsl_pwrscale_disable - temporarily disable the governor
  * @device: The device
@@ -852,6 +913,17 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
 			data->bin.ctxt_aware_busy_penalty = 12000;
 	}
 
+	if (of_property_read_bool(device->pdev->dev.of_node,
+			"qcom,enable-midframe-timer")) {
+		kgsl_midframe = kzalloc(
+				sizeof(struct kgsl_midframe_info), GFP_KERNEL);
+		hrtimer_init(&kgsl_midframe->timer,
+				CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		kgsl_midframe->timer.function =
+				kgsl_pwrscale_midframe_timer;
+		kgsl_midframe->device = device;
+	}
+
 	/*
 	 * If there is a separate GX power rail, allow
 	 * independent modification to its voltage through
@@ -900,6 +972,9 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
 	INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
 	INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
 	INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
+	if (kgsl_midframe)
+		INIT_WORK(&kgsl_midframe->timer_check_ws,
+				kgsl_pwrscale_midframe_timer_check);
 
 	pwrscale->next_governor_call = ktime_add_us(ktime_get(),
 			KGSL_GOVERNOR_CALL_INTERVAL);
@@ -940,9 +1015,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
 	pwrscale = &device->pwrscale;
 	if (!pwrscale->devfreqptr)
 		return;
+
+	kgsl_pwrscale_midframe_timer_cancel(device);
 	flush_workqueue(pwrscale->devfreq_wq);
 	destroy_workqueue(pwrscale->devfreq_wq);
 	devfreq_remove_device(device->pwrscale.devfreqptr);
+	kfree(kgsl_midframe);
+	kgsl_midframe = NULL;
 	device->pwrscale.devfreqptr = NULL;
 	srcu_cleanup_notifier_head(&device->pwrscale.nh);
 	for (i = 0; i < KGSL_PWREVENT_MAX; i++)
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index 0756a4490f22..184bfd1a2692 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -122,6 +122,9 @@ void kgsl_pwrscale_busy(struct kgsl_device *device);
 void kgsl_pwrscale_sleep(struct kgsl_device *device);
 void kgsl_pwrscale_wake(struct kgsl_device *device);
 
+void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device);
+void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device);
+
 void kgsl_pwrscale_enable(struct kgsl_device *device);
 void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo);