Merge "msm: dcvs: set gpu frequency floor when multiple CPUs online"
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 14edbcf..f559629 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2735,6 +2735,7 @@
 static struct msm_dcvs_platform_data apq8064_dcvs_data = {
 	.sync_rules	= apq8064_dcvs_sync_rules,
 	.num_sync_rules = ARRAY_SIZE(apq8064_dcvs_sync_rules),
+	.gpu_max_nom_khz = 320000,
 };
 
 struct platform_device apq8064_dcvs_device = {
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index c29b57a..49841ea 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -44,6 +44,7 @@
 struct msm_dcvs_platform_data {
 	struct msm_dcvs_sync_rule *sync_rules;
 	unsigned num_sync_rules;
+	unsigned long gpu_max_nom_khz;
 };
 
 struct msm_gov_platform_data {
@@ -154,4 +155,13 @@
  * Update the frequency known to dcvs when the limits are changed.
  */
 extern void msm_dcvs_update_limits(int dcvs_core_id);
+
+/**
+ * msm_dcvs_apply_gpu_floor
+ * @cpu_freq: CPU frequency to compare to GPU sync rules
+ *
+ * Apply a GPU floor frequency if the corresponding CPU frequency,
+ * or the number of CPUs online, requires it.
+ */
+extern void msm_dcvs_apply_gpu_floor(unsigned long cpu_freq);
 #endif
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9bc85e5..13cc170 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -258,36 +258,49 @@
 	spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
 }
 
-static void apply_gpu_floor(int cpu_freq)
+void msm_dcvs_apply_gpu_floor(unsigned long cpu_freq)
 {
-	int i;
-	int gpu_floor_freq = 0;
+	static unsigned long curr_cpu0_freq;
+	unsigned long gpu_floor_freq = 0;
 	struct dcvs_core *gpu;
+	int i;
 
 	if (!dcvs_pdata)
 		return;
 
+	mutex_lock(&gpu_floor_mutex);
+
+	if (cpu_freq)
+		curr_cpu0_freq = cpu_freq;
+
 	for (i = 0; i < dcvs_pdata->num_sync_rules; i++)
-		if (cpu_freq > dcvs_pdata->sync_rules[i].cpu_khz) {
+		if (curr_cpu0_freq > dcvs_pdata->sync_rules[i].cpu_khz) {
 			gpu_floor_freq =
 				dcvs_pdata->sync_rules[i].gpu_floor_khz;
 			break;
 		}
 
-	if (!gpu_floor_freq)
+	if (num_online_cpus() > 1)
+		gpu_floor_freq = max(gpu_floor_freq,
+				     dcvs_pdata->gpu_max_nom_khz);
+
+	if (!gpu_floor_freq) {
+		mutex_unlock(&gpu_floor_mutex);
 		return;
+	}
 
 	for (i = GPU_OFFSET; i < CORES_MAX; i++) {
 		gpu = &core_list[i];
 		if (gpu->dcvs_core_id == -1)
 			continue;
-		mutex_lock(&gpu_floor_mutex);
+
 		if (gpu->pending_freq != STOP_FREQ_CHANGE &&
 		    gpu->set_floor_frequency)
 			gpu->set_floor_frequency(gpu->type_core_num,
 						 gpu_floor_freq);
-		mutex_unlock(&gpu_floor_mutex);
 	}
+
+	mutex_unlock(&gpu_floor_mutex);
 }
 
 static int __msm_dcvs_change_freq(struct dcvs_core *core)
@@ -318,7 +331,7 @@
 
 	if (core->type == MSM_DCVS_CORE_TYPE_CPU &&
 	    core->type_core_num == 0)
-		apply_gpu_floor(requested_freq);
+		msm_dcvs_apply_gpu_floor(requested_freq);
 
 	/**
 	 * Call the frequency sink driver to change the frequency
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index 407be6a..d906b51 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -391,6 +391,7 @@
 					break;
 				}
 		msm_mpd.hpupdate = HPUPDATE_WAITING;
+		msm_dcvs_apply_gpu_floor(0);
 	}
 
 	return 0;