--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1532,6 +1532,35 @@ config MSM_MPDEC
This enables kernel based multi core control.
(up/down hotplug based on load)
+config MSM_MPDEC_STARTDELAY
+ int "Starup delay for MPDECISION (ms)"
+ depends on MSM_MPDEC
+ default 20000
+
+config MSM_MPDEC_DELAY
+ int "MPDECISION Delay (ms)"
+ depends on MSM_MPDEC
+ default 70
+
+config MSM_MPDEC_PAUSE
+ int "MPDECISION Pause (ms)"
+ depends on MSM_MPDEC
+ default 10000
+
+config MSM_MPDEC_IDLE_FREQ
+ int "MPDECISION Idle Frequency (khz)"
+ depends on MSM_MPDEC
+ default 486000
+
+config MSM_MPDEC_SCROFF_FREQ
+ int "Max frequency when screen is off (khz)"
+ depends on MSM_MPDEC
+ default 486000
+
+config MSM_MPDEC_SCROFF_BOOT_DELAY
+ int "Disable Screen off for X seconds after boot"
+ depends on MSM_MPDEC
+ default 600
if CPU_FREQ_MSM
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -37,11 +37,12 @@
#define DEBUG 0
-#define MPDEC_TAG "[AnThRaX MPDEC]: "
-#define MSM_MPDEC_STARTDELAY 20000
-#define MSM_MPDEC_DELAY 70
-#define MSM_MPDEC_PAUSE 10000
-#define MSM_MPDEC_IDLE_FREQ 486000
+#define MPDEC_TAG "[MSM MPDEC]: "
+#define MSM_MPDEC_STARTDELAY CONFIG_MSM_MPDEC_STARTDELAY
+#define MSM_MPDEC_DELAY CONFIG_MSM_MPDEC_DELAY
+#define MSM_MPDEC_PAUSE CONFIG_MSM_MPDEC_PAUSE
+#define MSM_MPDEC_IDLE_FREQ CONFIG_MSM_MPDEC_IDLE_FREQ
+#define MSM_MPDEC_SCROFF_FREQ CONFIG_MSM_MPDEC_SCROFF_FREQ
enum {
MSM_MPDEC_DISABLED = 0,
@@ -53,8 +54,10 @@ enum {
struct msm_mpdec_cpudata_t {
struct mutex suspend_mutex;
int online;
- int device_suspended;
+ bool device_suspended;
cputime64_t on_time;
+ unsigned int max;
+ bool cpu_sleeping;
};
static DEFINE_PER_CPU(struct msm_mpdec_cpudata_t, msm_mpdec_cpudata);
@@ -67,7 +70,9 @@ static struct msm_mpdec_tuners {
unsigned int delay;
unsigned int pause;
bool scroff_single_core;
+ bool scroff_profile;
unsigned long int idle_freq;
+ unsigned long int scroff_freq;
unsigned int max_cpus;
unsigned int min_cpus;
} msm_mpdec_tuners_ins = {
@@ -75,7 +80,9 @@ static struct msm_mpdec_tuners {
.delay = MSM_MPDEC_DELAY,
.pause = MSM_MPDEC_PAUSE,
.scroff_single_core = true,
+ .scroff_profile = true,
.idle_freq = MSM_MPDEC_IDLE_FREQ,
+ .scroff_freq = MSM_MPDEC_SCROFF_FREQ,
.max_cpus = CONFIG_NR_CPUS,
.min_cpus = 1,
};
@@ -89,6 +96,20 @@ extern unsigned long acpuclk_get_rate(in
unsigned int state = MSM_MPDEC_IDLE;
bool was_paused = false;
+static void update_cpu_max_freq(int max_freq)
+{
+ pr_info(MPDEC_TAG"Update Max Freq enter --%d--\n", max_freq);
+
+ if (max_freq >= MAX_FREQ_LIMIT)
+ cpufreq_set_limit_defered(USER_MAX_STOP, max_freq);
+ else if (max_freq >= MIN_FREQ_LIMIT)
+ cpufreq_set_limit_defered(USER_MAX_START, max_freq);
+
+ pr_info(MPDEC_TAG"Update Max Freq leave --%d--\n", max_freq);
+
+ return;
+}
+
static unsigned long get_rate(int cpu)
{
return acpuclk_get_rate(cpu);
@@ -191,8 +212,8 @@ static int mp_decision(void)
last_time = ktime_to_ms(ktime_get());
#if DEBUG
- pr_info(MPDEC_TAG"[DEBUG] rq: %u, new_state: %i | Mask=[%d%d%d%d]\n",
- rq_depth, new_state, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
+ pr_info(MPDEC_TAG"[DEBUG] rq: %u, new_state: %i | Mask=[%d%d%d%d]\n",
+ rq_depth, new_state, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
#endif
return new_state;
}
@@ -289,50 +310,84 @@ out:
return;
}
+static int checkuptime(void)
+{
+ struct timespec uptime;
+
+ do_posix_clock_monotonic_gettime(&uptime);
+
+ if (uptime.tv_sec > CONFIG_MSM_MPDEC_SCROFF_BOOT_DELAY)
+ return 1;
+ else
+ return 0;
+}
+
static void msm_mpdec_early_suspend(struct early_suspend *h)
{
int cpu = nr_cpu_ids;
+ char cpu_mask[CONFIG_NR_CPUS +1] = "";
+ char cpu_online_string[2] = "";
+ struct cpufreq_policy *cpu_policy = NULL;
+
+ pr_info(MPDEC_TAG"Screen -> off.\n");
for_each_possible_cpu(cpu) {
mutex_lock(&per_cpu(msm_mpdec_cpudata, cpu).suspend_mutex);
if ((cpu >= 1) && (cpu_online(cpu))) {
cpu_down(cpu);
- pr_info(MPDEC_TAG"Screen -> off. Suspended CPU[%d] | Mask=[%d%d%d%d]\n",
- cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
+ pr_info(MPDEC_TAG"Screen -> off. Suspended CPU%d.\n", cpu);
per_cpu(msm_mpdec_cpudata, cpu).online = false;
}
+ if ((cpu_online(cpu) == 1) && (msm_mpdec_tuners_ins.scroff_profile) && (checkuptime())) {
+ cpu_policy = cpufreq_cpu_get(cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).max = cpu_policy->max;
+ update_cpu_max_freq(msm_mpdec_tuners_ins.scroff_freq);
+ pr_info(MPDEC_TAG"Entered sleep profile on CPU%d successfully.\n", cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).cpu_sleeping = true;
+ }
per_cpu(msm_mpdec_cpudata, cpu).device_suspended = true;
+ sprintf(cpu_online_string, "%d", cpu_online(cpu));
+ strncat(cpu_mask,cpu_online_string,1);
mutex_unlock(&per_cpu(msm_mpdec_cpudata, cpu).suspend_mutex);
}
/* main work thread can sleep now */
cancel_delayed_work_sync(&msm_mpdec_work);
- pr_info(MPDEC_TAG"Screen -> off. Deactivated mpdecision.\n");
+ pr_info(MPDEC_TAG"CPU Mask = [%s].\n",cpu_mask);
}
static void msm_mpdec_late_resume(struct early_suspend *h)
{
int cpu = nr_cpu_ids;
- for_each_possible_cpu(cpu)
- per_cpu(msm_mpdec_cpudata, cpu).device_suspended = false;
+ char cpu_mask[CONFIG_NR_CPUS +1] = "";
+ char cpu_online_string[2] = "";
- mutex_lock(&per_cpu(msm_mpdec_cpudata, 1).suspend_mutex);
- if (!cpu_online(1)) {
- /* Always enable cpu1 when screen comes online.
- * This boosts the wakeup process. */
- cpu_up(1);
- per_cpu(msm_mpdec_cpudata, 1).on_time = ktime_to_ms(ktime_get());
- per_cpu(msm_mpdec_cpudata, 1).online = true;
- pr_info(MPDEC_TAG"Screen -> on. Hot plugged CPU1 | Mask=[%d%d%d%d]\n",
- cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
+ pr_info(MPDEC_TAG"Screen -> on.\n");
+ for_each_possible_cpu(cpu) {
+ mutex_lock(&per_cpu(msm_mpdec_cpudata, 1).suspend_mutex);
+ per_cpu(msm_mpdec_cpudata, cpu).device_suspended = false;
+ if ((cpu_online(cpu) == 1) && (msm_mpdec_tuners_ins.scroff_profile) && (checkuptime())) {
+ update_cpu_max_freq(per_cpu(msm_mpdec_cpudata, cpu).max);
+ pr_info(MPDEC_TAG"Entered wake profile on CPU%d successfully.\n", cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).cpu_sleeping = false;
+ }
+ if (!cpu_online(cpu)) {
+ /* Turn on all cpus when the screen comes on
+ * This boost the wakeup process. */
+ cpu_up(cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).on_time = ktime_to_ms(ktime_get());
+ per_cpu(msm_mpdec_cpudata, cpu).online = true;
+ }
+ sprintf(cpu_online_string, "%d", cpu_online(cpu));
+ strncat(cpu_mask,cpu_online_string,1);
+ mutex_unlock(&per_cpu(msm_mpdec_cpudata, 1).suspend_mutex);
}
- mutex_unlock(&per_cpu(msm_mpdec_cpudata, 1).suspend_mutex);
+
+ pr_info(MPDEC_TAG"CPU Mask = [%s].\n",cpu_mask);
/* wake up main work thread */
was_paused = true;
queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work, 0);
- pr_info(MPDEC_TAG"Screen -> on. Activated mpdecision. | Mask=[%d%d%d%d]\n",
- cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
}
static struct early_suspend msm_mpdec_early_suspend_handler = {
@@ -357,6 +412,13 @@ show_one(pause, pause);
show_one(scroff_single_core, scroff_single_core);
show_one(min_cpus, min_cpus);
show_one(max_cpus, max_cpus);
+show_one(scroff_profile, scroff_profile);
+
+static ssize_t show_scroff_freq (struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%lu\n", msm_mpdec_tuners_ins.scroff_freq);
+}
#define show_one_twts(file_name, arraypos) \
static ssize_t show_##file_name \
@@ -513,6 +575,19 @@ static ssize_t store_idle_freq(struct ko
return count;
}
+static ssize_t store_scroff_freq(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ long unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%lu", &input);
+ if (ret != 1)
+ return -EINVAL;
+ msm_mpdec_tuners_ins.scroff_freq = input;
+
+ return count;
+}
+
static ssize_t store_scroff_single_core(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -562,6 +637,51 @@ static ssize_t store_min_cpus(struct kob
return count;
}
+static ssize_t store_scroff_profile(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ size_t ret = count;
+ int cpu;
+ struct cpufreq_policy *cpu_policy = NULL;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+ switch (buf[0]) {
+ case '0':
+ msm_mpdec_tuners_ins.scroff_profile = input;
+ break;
+ case '1':
+ msm_mpdec_tuners_ins.scroff_profile = input;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ for_each_possible_cpu(cpu) {
+ if (per_cpu(msm_mpdec_cpudata, cpu).device_suspended == true) {
+ if (per_cpu(msm_mpdec_cpudata, cpu).cpu_sleeping == true) {
+ if ((cpu_online(cpu) == 1) && (msm_mpdec_tuners_ins.scroff_profile == false) && (checkuptime())) {
+ update_cpu_max_freq(per_cpu(msm_mpdec_cpudata, cpu).max);
+ pr_info(MPDEC_TAG"Entered wake profile on CPU%d successfully.\n", cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).cpu_sleeping = false;
+ }
+ } else {
+ if ((cpu_online(cpu) == 1) && (msm_mpdec_tuners_ins.scroff_profile) && (checkuptime())) {
+ cpu_policy = cpufreq_cpu_get(cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).max = cpu_policy->max;
+ update_cpu_max_freq(msm_mpdec_tuners_ins.scroff_freq);
+ pr_info(MPDEC_TAG"Entered sleep profile on CPU%d successfully.\n", cpu);
+ per_cpu(msm_mpdec_cpudata, cpu).cpu_sleeping = true;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
static ssize_t store_enabled(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -605,8 +725,7 @@ static ssize_t store_enabled(struct kobj
case '1':
state = MSM_MPDEC_IDLE;
was_paused = true;
- queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work,
- msecs_to_jiffies(msm_mpdec_tuners_ins.delay));
+ queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work, msecs_to_jiffies(msm_mpdec_tuners_ins.delay));
pr_info(MPDEC_TAG" ENABLED mpdecision...\n");
break;
default:
@@ -619,7 +738,9 @@ define_one_global_rw(startdelay);
define_one_global_rw(delay);
define_one_global_rw(pause);
define_one_global_rw(scroff_single_core);
+define_one_global_rw(scroff_profile);
define_one_global_rw(idle_freq);
+define_one_global_rw(scroff_freq);
define_one_global_rw(min_cpus);
define_one_global_rw(max_cpus);
define_one_global_rw(enabled);
@@ -649,6 +770,8 @@ static struct attribute *msm_mpdec_attri
&nwns_threshold_5.attr,
&nwns_threshold_6.attr,
&nwns_threshold_7.attr,
+ &scroff_profile.attr,
+ &scroff_freq.attr,
NULL
};
@@ -684,13 +807,13 @@ static int __init msm_mpdec_init(void)
msm_mpdec_kobject = kobject_create_and_add("msm_mpdecision", kernel_kobj);
if (msm_mpdec_kobject) {
- rc = sysfs_create_group(msm_mpdec_kobject,
- &msm_mpdec_attr_group);
+ rc = sysfs_create_group(msm_mpdec_kobject, &msm_mpdec_attr_group);
if (rc) {
pr_warn(MPDEC_TAG"sysfs: ERROR, could not create sysfs group");
}
- } else
+ } else {
pr_warn(MPDEC_TAG"sysfs: ERROR, could not create sysfs kobj");
+ }
pr_info(MPDEC_TAG"%s init complete.", __func__);
@@ -704,4 +827,4 @@ void msm_mpdec_exit(void)
destroy_workqueue(msm_mpdec_workq);
}
-MODULE_DESCRIPTION("Kernel based MPDECISION (C) 2011-12 Chad Goodman");
+MODULE_DESCRIPTION("Kernel based MPDECISION (C) 2011-13 Chad Goodman");
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2106,6 +2106,7 @@ int cpufreq_set_limit_defered(unsigned i
return ret;
}
+EXPORT_SYMBOL(cpufreq_set_limit_defered);
#endif
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -341,17 +341,17 @@ static inline unsigned int cpufreq_quick
#ifdef CONFIG_SEC_DVFS
-#define TOUCH_BOOSTER_FIRST_FREQ_LIMIT 1134000
-#define TOUCH_BOOSTER_SECOND_FREQ_LIMIT 810000
-#define TOUCH_BOOSTER_FREQ_LIMIT 486000
+#define TOUCH_BOOSTER_FIRST_FREQ_LIMIT 1134000
+#define TOUCH_BOOSTER_SECOND_FREQ_LIMIT 810000
+#define TOUCH_BOOSTER_FREQ_LIMIT 486000
-#define LOW_MAX_FREQ_LIMIT 1188000
+#define LOW_MAX_FREQ_LIMIT 1188000
-#define MIN_FREQ_LIMIT CONFIG_CPU_FREQ_MIN_SCALING_LIMIT
-#define MAX_FREQ_LIMIT CONFIG_CPU_FREQ_MAX_SCALING_LIMIT
- #define FREQ_TABLE_SIZE 38
- #define FREQ_TABLE_SIZE_OFFSET 6
- #define FREQ_STEPS 30
+#define MIN_FREQ_LIMIT CONFIG_CPU_FREQ_MIN_SCALING_LIMIT
+#define MAX_FREQ_LIMIT CONFIG_CPU_FREQ_MAX_SCALING_LIMIT
+#define FREQ_TABLE_SIZE 38
+#define FREQ_TABLE_SIZE_OFFSET 6
+#define FREQ_STEPS 30
enum {
SET_MIN = 0,