summaryrefslogtreecommitdiffstats
path: root/power
diff options
context:
space:
mode:
authorSimon Shields <keepcalm444@gmail.com>2016-02-27 20:37:29 +1100
committerSimon Shields <keepcalm444@gmail.com>2016-03-02 23:28:11 +1100
commitbe4c4ec36f214eda40301450cd0691d08719852c (patch)
tree25d7be6eb8dd29299e7eb66059fd31f7be54eee6 /power
parentddc02ec2b3d19e301c4cb761b778f43ceff9f8ad (diff)
downloaddevice_samsung_i9300-be4c4ec36f214eda40301450cd0691d08719852c.zip
device_samsung_i9300-be4c4ec36f214eda40301450cd0691d08719852c.tar.gz
device_samsung_i9300-be4c4ec36f214eda40301450cd0691d08719852c.tar.bz2
i9300: power: pegasusq boosting support
implement INTERACTION, LAUNCH_BOOST, and CPU_BOOST hints. Change-Id: Iac8c84ecb910a72a6de4c81a470c9d2d800ff631
Diffstat (limited to 'power')
-rw-r--r--power/Android.mk2
-rw-r--r--power/power.c80
-rw-r--r--power/power.h27
3 files changed, 98 insertions, 11 deletions
diff --git a/power/Android.mk b/power/Android.mk
index 0cb4890..af65a3c 100644
--- a/power/Android.mk
+++ b/power/Android.mk
@@ -18,6 +18,8 @@ ifeq ($(TARGET_POWERHAL_VARIANT),pegasusq)
include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DUSE_PEGASUSQ_BOOSTING
+
LOCAL_MODULE := power.$(TARGET_BOOTLOADER_BOARD_NAME)
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SHARED_LIBRARIES := liblog libcutils
diff --git a/power/power.c b/power/power.c
index f5df011..278994e 100644
--- a/power/power.c
+++ b/power/power.c
@@ -35,10 +35,13 @@
#define PEGASUSQ_PATH "/sys/devices/system/cpu/cpufreq/pegasusq/"
#define MINMAX_CPU_PATH "/sys/power/"
+#define US_TO_NS (1000L)
+
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int current_power_profile = -1;
static bool is_low_power = false;
+static bool is_vsync_active = false;
static int sysfs_write_str(char *path, char *s) {
char buf[80];
@@ -70,6 +73,13 @@ static int sysfs_write_int(char *path, int value) {
snprintf(buf, 80, "%d", value);
return sysfs_write_str(path, buf);
}
+
+static int sysfs_write_long(char *path, long value) {
+ char buf[80];
+ snprintf(buf, 80, "%ld", value);
+ return sysfs_write_str(path, buf);
+}
+
#ifdef LOG_NDEBUG
#define WRITE_PEGASUSQ_PARAM(profile, param) do { \
ALOGV("%s: WRITE_PEGASUSQ_PARAM(profile=%d, param=%s): new val => %d", __func__, profile, #param, profiles[profile].param); \
@@ -136,6 +146,8 @@ static void set_power_profile(int profile) {
WRITE_PEGASUSQ_PARAM(profile, cpu_down_rate);
WRITE_PEGASUSQ_PARAM(profile, sampling_rate);
WRITE_PEGASUSQ_PARAM(profile, io_is_busy);
+ WRITE_PEGASUSQ_PARAM(profile, boost_freq);
+ WRITE_PEGASUSQ_PARAM(profile, boost_mincpus);
current_power_profile = profile;
@@ -143,6 +155,24 @@ static void set_power_profile(int profile) {
}
+static void boost(long boost_time) {
+#ifdef USE_PEGASUSQ_BOOSTING
+ if (is_vsync_active) return;
+ if (boost_time == -1) {
+ sysfs_write_int(PEGASUSQ_PATH "boost_lock_time", -1);
+ } else {
+ sysfs_write_long(PEGASUSQ_PATH "boost_lock_time", boost_time);
+ }
+#endif
+}
+
+static void end_boost() {
+#ifdef USE_PEGASUSQ_BOOSTING
+ if (is_vsync_active) return;
+ sysfs_write_int(PEGASUSQ_PATH "boost_lock_time", 0);
+#endif
+}
+
static void set_low_power(bool low_power) {
if (!is_profile_valid(current_power_profile)) {
ALOGV("%s: current_power_profile not set yet", __func__);
@@ -154,6 +184,8 @@ static void set_low_power(bool low_power) {
if (is_low_power == low_power) return;
if (low_power) {
+ end_boost();
+
WRITE_LOW_POWER_PARAM(current_power_profile, hotplug_freq_1_1);
WRITE_LOW_POWER_PARAM(current_power_profile, hotplug_freq_2_0);
WRITE_LOW_POWER_PARAM(current_power_profile, hotplug_freq_2_1);
@@ -198,6 +230,9 @@ static void set_low_power(bool low_power) {
WRITE_PEGASUSQ_PARAM(current_power_profile, cpu_down_rate);
WRITE_PEGASUSQ_PARAM(current_power_profile, sampling_rate);
WRITE_PEGASUSQ_PARAM(current_power_profile, io_is_busy);
+ WRITE_PEGASUSQ_PARAM(current_power_profile, boost_freq);
+ WRITE_PEGASUSQ_PARAM(current_power_profile, boost_mincpus);
+
is_low_power = false;
}
}
@@ -288,21 +323,44 @@ static void power_set_interactive(__attribute__((unused)) struct power_module *m
* integer value of the boost duration in microseconds.
*/
static void power_hint(__attribute__((unused)) struct power_module *module, power_hint_t hint, void *data) {
+ if (hint == POWER_HINT_SET_PROFILE) {
+ ALOGV("%s: set profile %d", __func__, *(int32_t *)data);
+ pthread_mutex_lock(&lock);
+ if (is_vsync_active) {
+ is_vsync_active = false;
+ end_boost();
+ }
+ set_power_profile(*(int32_t *)data);
+ pthread_mutex_unlock(&lock);
+ }
+
+ if (current_power_profile == PROFILE_POWER_SAVE) return;
+
+ pthread_mutex_lock(&lock);
+
switch (hint) {
- case POWER_HINT_SET_PROFILE:
- ALOGV("%s: set profile %d", __func__, *(int32_t *)data);
- pthread_mutex_lock(&lock);
- set_power_profile(*(int32_t *)data);
- pthread_mutex_unlock(&lock);
- break;
case POWER_HINT_INTERACTION:
- case POWER_HINT_VSYNC:
+ case POWER_HINT_LAUNCH_BOOST:
+ ALOGV("%s: interaction/launch", __func__);
+ boost(profiles[current_power_profile].interaction_boost_time);
+ break;
+/* case POWER_HINT_VSYNC:
+ if (*(int32_t *)data) {
+ ALOGV("%s: vsync", __func__);
+ boost(-1);
+ is_vsync_active = true;
+ } else {
+ is_vsync_active = false;
+ end_boost();
+ }
+ break;*/
+ case POWER_HINT_CPU_BOOST:
+ ALOGV("%s: cpu_boost", __func__);
+ boost((*(int32_t *)data) * US_TO_NS);
break;
- case POWER_HINT_LOW_POWER:
- break;
- default:
- break;
}
+
+ pthread_mutex_unlock(&lock);
}
/*
diff --git a/power/power.h b/power/power.h
index db031cf..08ceb51 100644
--- a/power/power.h
+++ b/power/power.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define MS_TO_NS (1000000L)
+
enum {
PROFILE_POWER_SAVE = 0,
PROFILE_BALANCED,
@@ -50,6 +52,10 @@ typedef struct governor_settings {
int cpu_down_rate;
int sampling_rate; // in microseconds
int io_is_busy;
+ // boosting
+ int boost_freq;
+ int boost_mincpus;
+ long interaction_boost_time;
} power_profile;
static power_profile profiles[PROFILE_MAX] = {
@@ -75,6 +81,10 @@ static power_profile profiles[PROFILE_MAX] = {
.cpu_down_rate = 5,
.sampling_rate = 200000,
.io_is_busy = 0,
+ // nb: boosting power hints are ignored for PROFILE_POWER_SAVE
+ .boost_freq = 0,
+ .boost_mincpus = 0,
+ .interaction_boost_time = 0,
},
[PROFILE_BALANCED] = {
.hotplug_freq_1_1 = 500000,
@@ -98,6 +108,9 @@ static power_profile profiles[PROFILE_MAX] = {
.cpu_down_rate = 10,
.sampling_rate = 200000,
.io_is_busy = 0,
+ .boost_freq = 700000,
+ .boost_mincpus = 0,
+ .interaction_boost_time = 60 * (MS_TO_NS),
},
[PROFILE_PERFORMANCE] = {
.hotplug_freq_1_1 = 500000,
@@ -121,9 +134,14 @@ static power_profile profiles[PROFILE_MAX] = {
.cpu_down_rate = 20,
.sampling_rate = 200000,
.io_is_busy = 1,
+ .boost_freq = 900000,
+ .boost_mincpus = 2,
+ .interaction_boost_time = 90 * (MS_TO_NS),
},
};
+// for non-interactive profiles we don't need to worry about
+// boosting as it (should) only occur while the screen is on
static power_profile profiles_low_power[PROFILE_MAX] = {
[PROFILE_POWER_SAVE] = {
.hotplug_freq_1_1 = 800000,
@@ -147,6 +165,9 @@ static power_profile profiles_low_power[PROFILE_MAX] = {
.cpu_down_rate = 5,
.sampling_rate = 200000,
.io_is_busy = 0,
+ .boost_freq = 0,
+ .boost_mincpus = 0,
+ .interaction_boost_time = 0,
},
[PROFILE_BALANCED] = {
.hotplug_freq_1_1 = 700000,
@@ -170,6 +191,9 @@ static power_profile profiles_low_power[PROFILE_MAX] = {
.cpu_down_rate = 8,
.sampling_rate = 200000,
.io_is_busy = 0,
+ .boost_freq = 0,
+ .boost_mincpus = 0,
+ .interaction_boost_time = 0,
},
[PROFILE_PERFORMANCE] = {
.hotplug_freq_1_1 = 800000,
@@ -193,6 +217,9 @@ static power_profile profiles_low_power[PROFILE_MAX] = {
.cpu_down_rate = 15,
.sampling_rate = 200000,
.io_is_busy = 1,
+ .boost_freq = 0,
+ .boost_mincpus = 0,
+ .interaction_boost_time = 0,
},
};