From 450b22e9aea979d3dada4b470e672b5733c0461a Mon Sep 17 00:00:00 2001 From: tarun93 Date: Fri, 12 Feb 2016 02:22:05 +0530 Subject: [PATCH] ElementalX governor version 2 Signed-off-by: tarun93 --- arch/arm/configs/g620s_defconfig | 6 +- drivers/cpufreq/Kconfig | 20 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq_elementalx.c | 589 +++++++++++++++++++++++++++ drivers/cpufreq/cpufreq_governor.c | 19 + drivers/cpufreq/cpufreq_governor.h | 20 + drivers/gpu/msm/kgsl_pwrctrl.c | 7 + include/linux/msm_kgsl.h | 4 + 8 files changed, 664 insertions(+), 2 deletions(-) create mode 100644 drivers/cpufreq/cpufreq_elementalx.c diff --git a/arch/arm/configs/g620s_defconfig b/arch/arm/configs/g620s_defconfig index f834dd01a9ea..b23a59b4c446 100644 --- a/arch/arm/configs/g620s_defconfig +++ b/arch/arm/configs/g620s_defconfig @@ -581,7 +581,8 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_DEFAULT_GOV_ZZMOOVE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_YANKACTIVE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_BIOSHOCK is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ELEMENTALX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_DARKNESS is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -591,7 +592,8 @@ CONFIG_CPU_FREQ_GOV_IMPULSE=y CONFIG_CPU_FREQ_GOV_ZZMOOVE=y CONFIG_CPU_FREQ_GOV_YANKACTIVE=y CONFIG_CPU_FREQ_GOV_BIOSHOCK=y -CONFIG_CPU_FREQ_GOV_HYPER=y +CONFIG_CPU_FREQ_GOV_ELEMENTALX=y +CONFIG_CPU_FREQ_GOV_DARKNESS=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set CONFIG_CPU_BOOST=y diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index b4738d27ede8..2e719e35e21c 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -97,6 +97,13 @@ config CPU_FREQ_DEFAULT_GOV_ONDEMAND governor. If unsure have a look at the help section of the driver. Fallback governor will be the performance governor. +config CPU_FREQ_DEFAULT_GOV_ELEMENTALX + bool "elementalx" + select CPU_FREQ_GOV_ELEMENTALX + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'elementalx' as default. + config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE bool "conservative" select CPU_FREQ_GOV_CONSERVATIVE @@ -216,6 +223,19 @@ config CPU_FREQ_GOV_ONDEMAND If in doubt, say N. +config CPU_FREQ_GOV_ELEMENTALX + tristate "'elementalx' cpufreq policy governor" + select CPU_FREQ_TABLE + help + 'elementalx' - This driver adds a dynamic cpufreq policy governor. + + To compile this driver as a module, choose M here: the + module will be called cpufreq_elementalx. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + config CPU_FREQ_GOV_INTERACTIVE tristate "'interactive' cpufreq policy governor" help diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index fa2308701a8b..0d9372df2251 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o +obj-$(CONFIG_CPU_FREQ_GOV_ELEMENTALX) += cpufreq_elementalx.o obj-$(CONFIG_CPU_FREQ_GOV_IMPULSE) += cpufreq_impulse.o obj-$(CONFIG_CPU_FREQ_GOV_ZZMOOVE) += cpufreq_zzmoove.o obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o diff --git a/drivers/cpufreq/cpufreq_elementalx.c b/drivers/cpufreq/cpufreq_elementalx.c new file mode 100644 index 000000000000..8d3203093a50 --- /dev/null +++ b/drivers/cpufreq/cpufreq_elementalx.c @@ -0,0 +1,589 @@ +/* + * drivers/cpufreq/cpufreq_elementalx.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi + * Jun Nakajima + * (C) 2015 Aaron Segaert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include "cpufreq_governor.h" + +/* elementalx governor macros */ +#define DEF_FREQUENCY_UP_THRESHOLD (90) +#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (20) +#define DEF_ACTIVE_FLOOR_FREQ (800000) +#define DEF_GBOOST_MIN_FREQ (998400) +#define DEF_MAX_SCREEN_OFF_FREQ (1094400) +#define MIN_SAMPLING_RATE (10000) +#define DEF_SAMPLING_DOWN_FACTOR (8) +#define MAX_SAMPLING_DOWN_FACTOR (20) +#define FREQ_NEED_BURST(x) (x < 600000 ? 1 : 0) +#define MAX(x,y) (x > y ? x : y) +#define MIN(x,y) (x < y ? x : y) +#define TABLE_SIZE 5 + +static DEFINE_PER_CPU(struct ex_cpu_dbs_info_s, ex_cpu_dbs_info); + +static unsigned int up_threshold_level[2] __read_mostly = {95, 85}; +static struct cpufreq_frequency_table *tbl = NULL; +static unsigned int *tblmap[TABLE_SIZE] __read_mostly; +static unsigned int tbl_select[4]; + +static struct ex_governor_data { + unsigned int active_floor_freq; + unsigned int max_screen_off_freq; + unsigned int prev_load; + unsigned int g_count; + bool suspended; + struct notifier_block notif; +} ex_data = { + .active_floor_freq = DEF_ACTIVE_FLOOR_FREQ, + .max_screen_off_freq = DEF_MAX_SCREEN_OFF_FREQ, + .prev_load = 0, + .g_count = 0, + .suspended = false +}; + +static void dbs_init_freq_map_table(void) +{ + unsigned int min_diff, top1, top2; + int cnt, i, j; + struct cpufreq_policy *policy; + + policy = cpufreq_cpu_get(0); + tbl = cpufreq_frequency_get_table(0); + min_diff = policy->cpuinfo.max_freq; + + for (cnt = 0; (tbl[cnt].frequency != CPUFREQ_TABLE_END); cnt++) { + if (cnt > 0) + min_diff = MIN(tbl[cnt].frequency - tbl[cnt-1].frequency, min_diff); + } + + top1 = (policy->cpuinfo.max_freq + policy->cpuinfo.min_freq) / 2; + top2 = (policy->cpuinfo.max_freq + top1) / 2; + + for (i = 0; i < TABLE_SIZE; i++) { + tblmap[i] = kmalloc(sizeof(unsigned int) * cnt, GFP_KERNEL); + BUG_ON(!tblmap[i]); + for (j = 0; j < cnt; j++) + tblmap[i][j] = tbl[j].frequency; + } + + for (j = 0; j < cnt; j++) { + if (tbl[j].frequency < top1) { + tblmap[0][j] += MAX((top1 - tbl[j].frequency)/3, min_diff); + } + + if (tbl[j].frequency < top2) { + tblmap[1][j] += MAX((top2 - tbl[j].frequency)/3, min_diff); + tblmap[2][j] += MAX(((top2 - tbl[j].frequency)*2)/5, min_diff); + tblmap[3][j] += MAX((top2 - tbl[j].frequency)/2, min_diff); + } else { + tblmap[3][j] += MAX((policy->cpuinfo.max_freq - tbl[j].frequency)/3, min_diff); + } + + tblmap[4][j] += MAX((policy->cpuinfo.max_freq - tbl[j].frequency)/2, min_diff); + } + + tbl_select[0] = 0; + tbl_select[1] = 1; + tbl_select[2] = 2; + tbl_select[3] = 4; +} + +static void dbs_deinit_freq_map_table(void) +{ + int i; + + if (!tbl) + return; + + tbl = NULL; + + for (i = 0; i < TABLE_SIZE; i++) + kfree(tblmap[i]); +} + +static inline int get_cpu_freq_index(unsigned int freq) +{ + static int saved_index = 0; + int index; + + if (!tbl) { + pr_warn("tbl is NULL, use previous value %d\n", saved_index); + return saved_index; + } + + for (index = 0; (tbl[index].frequency != CPUFREQ_TABLE_END); index++) { + if (tbl[index].frequency >= freq) { + saved_index = index; + break; + } + } + + return index; +} + +static inline unsigned int ex_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ + if (freq > p->max) { + return p->max; + } + + else if (ex_data.suspended) { + freq = MIN(freq, ex_data.max_screen_off_freq); + } + + return freq; +} + +static void ex_check_cpu(int cpu, unsigned int load) +{ + struct ex_cpu_dbs_info_s *dbs_info = &per_cpu(ex_cpu_dbs_info, cpu); + struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + struct dbs_data *dbs_data = policy->governor_data; + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int max_load_freq = 0, freq_next = 0; + unsigned int j, avg_load, cur_freq, max_freq, target_freq = 0; + + cpufreq_notify_utilization(policy, load); + + cur_freq = policy->cur; + max_freq = policy->max; + + for_each_cpu(j, policy->cpus) { + if (load > max_load_freq) + max_load_freq = load * policy->cur; + } + avg_load = (ex_data.prev_load + load) >> 1; + + if (ex_tuners->gboost) { + if (ex_data.g_count < 500 && graphics_boost < 3) + ++ex_data.g_count; + else if (ex_data.g_count > 1) + --ex_data.g_count; + } + + //gboost mode + if (ex_tuners->gboost && ex_data.g_count > 300) { + + if (avg_load > 40 + (graphics_boost * 10)) { + freq_next = max_freq; + } else { + freq_next = max_freq * avg_load / 100; + freq_next = MAX(freq_next, ex_tuners->gboost_min_freq); + } + + target_freq = ex_freq_increase(policy, freq_next); + + __cpufreq_driver_target(policy, target_freq, CPUFREQ_RELATION_H); + + goto finished; + } + + //normal mode + if (max_load_freq > up_threshold_level[1] * cur_freq) { + int index = get_cpu_freq_index(cur_freq); + + if (FREQ_NEED_BURST(cur_freq) && + load > up_threshold_level[0]) { + freq_next = max_freq; + } + + else if (avg_load > up_threshold_level[0]) { + freq_next = tblmap[tbl_select[3]][index]; + } + + else if (avg_load <= up_threshold_level[1]) { + freq_next = tblmap[tbl_select[1]][index]; + } + + else { + if (load > up_threshold_level[0]) { + freq_next = tblmap[tbl_select[3]][index]; + } + + else { + freq_next = tblmap[tbl_select[2]][index]; + } + } + + target_freq = ex_freq_increase(policy, freq_next); + + __cpufreq_driver_target(policy, target_freq, CPUFREQ_RELATION_H); + + if (target_freq > ex_data.active_floor_freq) + dbs_info->down_floor = 0; + + goto finished; + } + + if (cur_freq == policy->min) + goto finished; + + if (cur_freq >= ex_data.active_floor_freq) { + if (++dbs_info->down_floor > ex_tuners->sampling_down_factor) + dbs_info->down_floor = 0; + } else { + dbs_info->down_floor = 0; + } + + if (max_load_freq < + (ex_tuners->up_threshold - ex_tuners->down_differential) * + cur_freq) { + + freq_next = max_load_freq / + (ex_tuners->up_threshold - + ex_tuners->down_differential); + + if (dbs_info->down_floor && !ex_data.suspended) { + freq_next = MAX(freq_next, ex_data.active_floor_freq); + } else { + freq_next = MAX(freq_next, policy->min); + if (freq_next < ex_data.active_floor_freq) + dbs_info->down_floor = ex_tuners->sampling_down_factor; + } + + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } + +finished: + ex_data.prev_load = load; + return; +} + +static void ex_dbs_timer(struct work_struct *work) +{ + struct ex_cpu_dbs_info_s *dbs_info = container_of(work, + struct ex_cpu_dbs_info_s, cdbs.work.work); + unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; + struct ex_cpu_dbs_info_s *core_dbs_info = &per_cpu(ex_cpu_dbs_info, + cpu); + struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data; + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + int delay = delay_for_sampling_rate(ex_tuners->sampling_rate); + bool modify_all = true; + + mutex_lock(&core_dbs_info->cdbs.timer_mutex); + if (!need_load_eval(&core_dbs_info->cdbs, ex_tuners->sampling_rate)) + modify_all = false; + else + dbs_check_cpu(dbs_data, cpu); + + gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all); + mutex_unlock(&core_dbs_info->cdbs.timer_mutex); +} + +static int fb_notifier_callback(struct notifier_block *this, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + + if (evdata && evdata->data && event == FB_EVENT_BLANK) { + blank = evdata->data; + switch (*blank) { + case FB_BLANK_UNBLANK: + //display on + ex_data.suspended = false; + break; + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + //display off + ex_data.suspended = true; + break; + } + } + + return NOTIFY_OK; +} + +/************************** sysfs interface ************************/ +static struct common_dbs_data ex_dbs_cdata; + +static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, + size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + ex_tuners->sampling_rate = max(input, dbs_data->min_sampling_rate); + return count; +} + +static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, + size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 100 || input <= ex_tuners->down_differential) + return -EINVAL; + + ex_tuners->up_threshold = input; + return count; +} + +static ssize_t store_down_differential(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 100 || input >= ex_tuners->up_threshold) + return -EINVAL; + + ex_tuners->down_differential = input; + return count; +} + +static ssize_t store_gboost(struct dbs_data *dbs_data, const char *buf, + size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 1) + return -EINVAL; + + if (input == 0) + ex_data.g_count = 0; + + ex_tuners->gboost = input; + return count; +} + +static ssize_t store_gboost_min_freq(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + ex_tuners->gboost_min_freq = input; + return count; +} + +static ssize_t store_active_floor_freq(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + ex_tuners->active_floor_freq = input; + ex_data.active_floor_freq = ex_tuners->active_floor_freq; + return count; +} + +static ssize_t store_max_screen_off_freq(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input == 0) + input = UINT_MAX; + + ex_tuners->max_screen_off_freq = input; + ex_data.max_screen_off_freq = ex_tuners->max_screen_off_freq; + return count; +} + +static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, + const char *buf, size_t count) +{ + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 0) + return -EINVAL; + + ex_tuners->sampling_down_factor = input; + return count; +} + +show_store_one(ex, sampling_rate); +show_store_one(ex, up_threshold); +show_store_one(ex, down_differential); +show_store_one(ex, gboost); +show_store_one(ex, gboost_min_freq); +show_store_one(ex, active_floor_freq); +show_store_one(ex, max_screen_off_freq); +show_store_one(ex, sampling_down_factor); +declare_show_sampling_rate_min(ex); + +gov_sys_pol_attr_rw(sampling_rate); +gov_sys_pol_attr_rw(up_threshold); +gov_sys_pol_attr_rw(down_differential); +gov_sys_pol_attr_rw(gboost); +gov_sys_pol_attr_rw(gboost_min_freq); +gov_sys_pol_attr_rw(active_floor_freq); +gov_sys_pol_attr_rw(max_screen_off_freq); +gov_sys_pol_attr_rw(sampling_down_factor); +gov_sys_pol_attr_ro(sampling_rate_min); + +static struct attribute *dbs_attributes_gov_sys[] = { + &sampling_rate_min_gov_sys.attr, + &sampling_rate_gov_sys.attr, + &up_threshold_gov_sys.attr, + &down_differential_gov_sys.attr, + &gboost_gov_sys.attr, + &gboost_min_freq_gov_sys.attr, + &active_floor_freq_gov_sys.attr, + &max_screen_off_freq_gov_sys.attr, + &sampling_down_factor_gov_sys.attr, + NULL +}; + +static struct attribute_group ex_attr_group_gov_sys = { + .attrs = dbs_attributes_gov_sys, + .name = "elementalx", +}; + +static struct attribute *dbs_attributes_gov_pol[] = { + &sampling_rate_min_gov_pol.attr, + &sampling_rate_gov_pol.attr, + &up_threshold_gov_pol.attr, + &down_differential_gov_pol.attr, + &gboost_gov_pol.attr, + &gboost_min_freq_gov_pol.attr, + &active_floor_freq_gov_pol.attr, + &max_screen_off_freq_gov_pol.attr, + &sampling_down_factor_gov_pol.attr, + NULL +}; + +static struct attribute_group ex_attr_group_gov_pol = { + .attrs = dbs_attributes_gov_pol, + .name = "elementalx", +}; + +/************************** sysfs end ************************/ + +static int ex_init(struct dbs_data *dbs_data) +{ + struct ex_dbs_tuners *tuners; + + tuners = kzalloc(sizeof(*tuners), GFP_KERNEL); + if (!tuners) { + pr_err("%s: kzalloc failed\n", __func__); + return -ENOMEM; + } + + tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD; + tuners->down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL; + tuners->ignore_nice_load = 0; + tuners->gboost = 1; + tuners->gboost_min_freq = DEF_GBOOST_MIN_FREQ; + tuners->active_floor_freq = DEF_ACTIVE_FLOOR_FREQ; + tuners->max_screen_off_freq = DEF_MAX_SCREEN_OFF_FREQ; + tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR; + + dbs_data->tuners = tuners; + dbs_data->min_sampling_rate = MIN_SAMPLING_RATE; + + dbs_init_freq_map_table(); + + ex_data.notif.notifier_call = fb_notifier_callback; + if (fb_register_client(&ex_data.notif)) + pr_err("%s: Failed to register fb_notifier\n", __func__); + + mutex_init(&dbs_data->mutex); + return 0; +} + +static void ex_exit(struct dbs_data *dbs_data) +{ + dbs_deinit_freq_map_table(); + fb_unregister_client(&ex_data.notif); + kfree(dbs_data->tuners); +} + +define_get_cpu_dbs_routines(ex_cpu_dbs_info); + +static struct common_dbs_data ex_dbs_cdata = { + .governor = GOV_ELEMENTALX, + .attr_group_gov_sys = &ex_attr_group_gov_sys, + .attr_group_gov_pol = &ex_attr_group_gov_pol, + .get_cpu_cdbs = get_cpu_cdbs, + .get_cpu_dbs_info_s = get_cpu_dbs_info_s, + .gov_dbs_timer = ex_dbs_timer, + .gov_check_cpu = ex_check_cpu, + .init = ex_init, + .exit = ex_exit, +}; + +static int ex_cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + return cpufreq_governor_dbs(policy, &ex_dbs_cdata, event); +} + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ELEMENTALX +static +#endif +struct cpufreq_governor cpufreq_gov_elementalx = { + .name = "elementalx", + .governor = ex_cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +static int __init cpufreq_gov_dbs_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_elementalx); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_elementalx); +} + +MODULE_AUTHOR("Aaron Segaert "); +MODULE_DESCRIPTION("'cpufreq_elementalx' - multiphase cpufreq governor"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ELEMENTALX +fs_initcall(cpufreq_gov_dbs_init); +#else +module_init(cpufreq_gov_dbs_init); +#endif +module_exit(cpufreq_gov_dbs_exit); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 1b44496b2d2b..7bb119bce561 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -35,6 +35,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; struct cpufreq_policy *policy; unsigned int sampling_rate; unsigned int max_load = 0; @@ -55,6 +56,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) sampling_rate *= od_dbs_info->rate_mult; ignore_nice = od_tuners->ignore_nice_load; + } else if (dbs_data->cdata->governor == GOV_ELEMENTALX) { + sampling_rate = ex_tuners->sampling_rate; + ignore_nice = ex_tuners->ignore_nice_load; } else { sampling_rate = cs_tuners->sampling_rate; ignore_nice = cs_tuners->ignore_nice_load; @@ -233,6 +237,9 @@ static void set_sampling_rate(struct dbs_data *dbs_data, if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; cs_tuners->sampling_rate = sampling_rate; + } else if (dbs_data->cdata->governor == GOV_ELEMENTALX) { + struct ex_dbs_tuners *ex_tuners = dbs_data->tuners; + ex_tuners->sampling_rate = sampling_rate; } else { struct od_dbs_tuners *od_tuners = dbs_data->tuners; od_tuners->sampling_rate = sampling_rate; @@ -245,9 +252,11 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct dbs_data *dbs_data; struct od_cpu_dbs_info_s *od_dbs_info = NULL; struct cs_cpu_dbs_info_s *cs_dbs_info = NULL; + struct ex_cpu_dbs_info_s *ex_dbs_info = NULL; struct od_ops *od_ops = NULL; struct od_dbs_tuners *od_tuners = NULL; struct cs_dbs_tuners *cs_tuners = NULL; + struct ex_dbs_tuners *ex_tuners = NULL; struct cpu_dbs_common_info *cpu_cdbs; unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu; int io_busy = 0; @@ -353,6 +362,11 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); sampling_rate = cs_tuners->sampling_rate; ignore_nice = cs_tuners->ignore_nice_load; + } else if (dbs_data->cdata->governor == GOV_ELEMENTALX) { + ex_tuners = dbs_data->tuners; + ex_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); + sampling_rate = ex_tuners->sampling_rate; + ignore_nice = ex_tuners->ignore_nice_load; } else { od_tuners = dbs_data->tuners; od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); @@ -397,6 +411,8 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, cs_dbs_info->down_skip = 0; cs_dbs_info->enable = 1; cs_dbs_info->requested_freq = policy->cur; + } else if (dbs_data->cdata->governor == GOV_ELEMENTALX) { + ex_dbs_info->enable = 1; } else { od_dbs_info->rate_mult = 1; od_dbs_info->sample_type = OD_NORMAL_SAMPLE; @@ -416,6 +432,9 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, if (dbs_data->cdata->governor == GOV_CONSERVATIVE) cs_dbs_info->enable = 0; + if (dbs_data->cdata->governor == GOV_ELEMENTALX) + ex_dbs_info->enable = 0; + gov_cancel_work(dbs_data, policy); mutex_lock(&dbs_data->mutex); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index cc401d147e72..60445dec91e5 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -126,6 +126,7 @@ static void *get_cpu_dbs_info_s(int cpu) \ * cdbs: common dbs * od_*: On-demand governor * cs_*: Conservative governor + * ex_*: ElementalX governor */ /* Per cpu structures */ @@ -169,6 +170,12 @@ struct cs_cpu_dbs_info_s { unsigned int enable:1; }; +struct ex_cpu_dbs_info_s { + struct cpu_dbs_common_info cdbs; + unsigned int down_floor; + unsigned int enable:1; +}; + /* Per policy Governors sysfs tunables */ struct od_dbs_tuners { unsigned int ignore_nice_load; @@ -188,12 +195,25 @@ struct cs_dbs_tuners { unsigned int freq_step; }; +struct ex_dbs_tuners { + unsigned int ignore_nice_load; + unsigned int sampling_rate; + unsigned int up_threshold; + unsigned int down_differential; + unsigned int gboost; + unsigned int gboost_min_freq; + unsigned int active_floor_freq; + unsigned int max_screen_off_freq; + unsigned int sampling_down_factor; +}; + /* Common Governor data across policies */ struct dbs_data; struct common_dbs_data { /* Common across governors */ #define GOV_ONDEMAND 0 #define GOV_CONSERVATIVE 1 + #define GOV_ELEMENTALX 2 int governor; struct attribute_group *attr_group_gov_sys; /* one governor - system */ struct attribute_group *attr_group_gov_pol; /* one governor - policy */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 939c0a2211ee..7b2f56622128 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -45,6 +45,10 @@ #define INIT_UDELAY 200 #define MAX_UDELAY 2000 +#ifdef CONFIG_CPU_FREQ_GOV_ELEMENTALX +int graphics_boost = 4; +#endif + /* Number of jiffies for a full thermal cycle */ #define TH_HZ 20 @@ -292,6 +296,9 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq); trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq); +#ifdef CONFIG_CPU_FREQ_GOV_ELEMENTALX + graphics_boost = pwr->active_pwrlevel; +#endif } EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change); diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h index 72db9803e31d..ee55c513e198 100644 --- a/include/linux/msm_kgsl.h +++ b/include/linux/msm_kgsl.h @@ -21,6 +21,10 @@ #define KGSL_3D0_SHADER_MEMORY "kgsl_3d0_shader_memory" #define KGSL_3D0_IRQ "kgsl_3d0_irq" +#ifdef CONFIG_CPU_FREQ_GOV_ELEMENTALX +extern int graphics_boost; +#endif + /** * struct kgsl_pwrlevel - Struct holding different pwrlevel info obtained from * from dtsi file