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>
(cherry picked from commit 682c7a01c1d86518cdc7bec25cb413498811137b)
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 44620a0..af26ec5 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2626,7 +2626,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;
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 6ddbf4e..8f086aa 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -253,6 +253,7 @@
msm_dcvs_freq_set,
msm_dcvs_freq_get,
msm_dcvs_idle_notifier,
+ NULL,
sensor);
if (gov->dcvs_core_id < 0) {
pr_err("Unable to register core for %d\n", cpu);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index b302bee..c680d57 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -23,6 +23,8 @@
struct kgsl_device *device;
int enabled;
unsigned int cur_freq;
+ unsigned int req_level;
+ int floor_level;
struct msm_dcvs_core_info *core_info;
int gpu_busy;
int dcvs_core_id;
@@ -69,7 +71,39 @@
return 0;
mutex_lock(&device->mutex);
- kgsl_pwrctrl_pwrlevel_change(device, i);
+ priv->req_level = i;
+ if (priv->req_level <= priv->floor_level) {
+ kgsl_pwrctrl_pwrlevel_change(device, priv->req_level);
+ priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
+ }
+ mutex_unlock(&device->mutex);
+
+ /* return current frequency in kHz */
+ return priv->cur_freq / 1000;
+}
+
+static int msm_set_min_freq(int core_num, unsigned int freq)
+{
+ int i, delta = 5000000;
+ struct msm_priv *priv = the_msm_priv;
+ struct kgsl_device *device = priv->device;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+ /* msm_dcvs manager uses frequencies in kHz */
+ freq *= 1000;
+ for (i = 0; i < pwr->num_pwrlevels; i++)
+ if (abs(pwr->pwrlevels[i].gpu_freq - freq) < delta)
+ break;
+ if (i == pwr->num_pwrlevels)
+ return 0;
+
+ mutex_lock(&device->mutex);
+ priv->floor_level = i;
+ if (priv->floor_level <= priv->req_level)
+ kgsl_pwrctrl_pwrlevel_change(device, priv->floor_level);
+ else if (priv->floor_level > priv->req_level)
+ kgsl_pwrctrl_pwrlevel_change(device, priv->req_level);
+
priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
mutex_unlock(&device->mutex);
@@ -170,6 +204,7 @@
priv->core_info = pdata->core_info;
tbl = priv->core_info->freq_tbl;
+ priv->floor_level = pwr->num_pwrlevels - 1;
/* Fill in frequency table from low to high, reversing order. */
low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
for (i = 0; i <= low_level; i++)
@@ -180,6 +215,7 @@
0,
priv->core_info,
msm_set_freq, msm_get_freq, msm_idle_enable,
+ msm_set_min_freq,
priv->core_info->sensors[0]);
if (priv->dcvs_core_id < 0) {
KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");