msm: dcvs: gpu minimum frequency levels

System performance is enhanced if the gpu frequency is given a
minimum corresponding to various frequency levels of CPU 0.

Change-Id: Iba168d708524fc8ef164428bb5f4e0631a499342
Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 3962a54..14edbcf 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2729,7 +2729,7 @@
 static struct msm_dcvs_sync_rule apq8064_dcvs_sync_rules[] = {
 	{1026000,	400000},
 	{384000,	200000},
-	{-1,		128000},
+	{0,		128000},
 };
 
 static struct msm_dcvs_platform_data apq8064_dcvs_data = {
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index 1ca5a32..c29b57a 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -122,6 +122,7 @@
 	unsigned int (*get_frequency)(int type_core_num),
 	int (*idle_enable)(int type_core_num,
 				enum msm_core_control_event event),
+	int (*set_floor_frequency)(int type_core_num, unsigned int freq),
 	int sensor);
 
 /**
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 358027c..86f4eaf 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -124,6 +124,7 @@
 	unsigned int (*get_frequency)(int type_core_num);
 	int (*idle_enable)(int type_core_num,
 			enum msm_core_control_event event);
+	int (*set_floor_frequency)(int type_core_num, unsigned int freq);
 
 	spinlock_t	pending_freq_lock;
 	int pending_freq;
@@ -252,6 +253,35 @@
 	spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
 }
 
+static void apply_gpu_floor(int cpu_freq)
+{
+	int i;
+	int gpu_floor_freq = 0;
+	struct dcvs_core *gpu;
+
+	if (!dcvs_pdata)
+		return;
+
+	for (i = 0; i < dcvs_pdata->num_sync_rules; i++)
+		if (cpu_freq > dcvs_pdata->sync_rules[i].cpu_khz) {
+			gpu_floor_freq =
+				dcvs_pdata->sync_rules[i].gpu_floor_khz;
+			break;
+		}
+
+	if (!gpu_floor_freq)
+		return;
+
+	for (i = GPU_OFFSET; i < CORES_MAX; i++) {
+		gpu = &core_list[i];
+		if (gpu->dcvs_core_id == -1)
+			continue;
+		if (gpu->set_floor_frequency)
+			gpu->set_floor_frequency(gpu->type_core_num,
+						 gpu_floor_freq);
+	}
+}
+
 static int __msm_dcvs_change_freq(struct dcvs_core *core)
 {
 	int ret = 0;
@@ -283,6 +313,10 @@
 
 	spin_unlock_irqrestore(&core->pending_freq_lock, flags);
 
+	if (core->type == MSM_DCVS_CORE_TYPE_CPU &&
+	    core->type_core_num == 0)
+		apply_gpu_floor(requested_freq);
+
 	/**
 	 * Call the frequency sink driver to change the frequency
 	 * We will need to get back the actual frequency in KHz and
@@ -871,6 +905,7 @@
 	unsigned int (*get_frequency)(int type_core_num),
 	int (*idle_enable)(int type_core_num,
 					enum msm_core_control_event event),
+	int (*set_floor_frequency)(int type_core_num, unsigned int freq),
 	int sensor)
 {
 	int ret = -EINVAL;
@@ -894,6 +929,7 @@
 	core->set_frequency = set_frequency;
 	core->get_frequency = get_frequency;
 	core->idle_enable = idle_enable;
+	core->set_floor_frequency = set_floor_frequency;
 	core->pending_freq = STOP_FREQ_CHANGE;
 
 	core->info = info;