diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c index 3962a542bde..14edbcfba95 100644 --- a/arch/arm/mach-msm/devices-8064.c +++ b/arch/arm/mach-msm/devices-8064.c @@ -2729,7 +2729,7 @@ struct platform_device i2s_mdm_8064_device = { 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 1ca5a321746..c29b57afb1e 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 @@ extern int msm_dcvs_register_core( 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 358027c140f..86f4eaff003 100644 --- a/arch/arm/mach-msm/msm_dcvs.c +++ b/arch/arm/mach-msm/msm_dcvs.c @@ -124,6 +124,7 @@ struct dcvs_core { 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 @@ static void restart_slack_timer(struct dcvs_core *core, int slack_us) 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 @@ repeat: 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 @@ int msm_dcvs_register_core( 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 @@ int msm_dcvs_register_core( 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 6ddbf4e4fa4..8f086aaa933 100644 --- a/drivers/cpufreq/cpufreq_gov_msm.c +++ b/drivers/cpufreq/cpufreq_gov_msm.c @@ -253,6 +253,7 @@ static int __devinit msm_gov_probe(struct platform_device *pdev) 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 b302beead91..c680d576117 100644 --- a/drivers/gpu/msm/kgsl_pwrscale_msm.c +++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c @@ -23,6 +23,8 @@ struct msm_priv { 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 @@ static int msm_set_freq(int core_num, unsigned int freq) 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 @@ static int msm_init(struct kgsl_device *device, 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 @@ static int msm_init(struct kgsl_device *device, 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");