blob: a2eb3732c64b08ce36486b3080d602e4c7a069c2 [file] [log] [blame]
John Stultz7266c5f2016-06-09 14:18:57 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Based on the FlounderPowerHAL
17 */
18
19#include <dirent.h>
20#include <errno.h>
21#include <string.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdbool.h>
John Stultz4c1a82b2016-08-18 14:49:01 -070028#include <pthread.h>
29#include <semaphore.h>
John Stultz7266c5f2016-06-09 14:18:57 -070030#include <cutils/properties.h>
31//#define LOG_NDEBUG 0
32
33#define LOG_TAG "HiKeyPowerHAL"
vishal7d9fede2018-06-05 12:43:23 +053034#include <log/log.h>
John Stultz7266c5f2016-06-09 14:18:57 -070035
36#include <hardware/hardware.h>
37#include <hardware/power.h>
38
John Stultzc1875b52018-11-20 16:15:20 -080039#include "power-helper.h"
40
John Stultz17e11242017-03-14 18:14:24 -070041#define SCHEDTUNE_BOOST_PATH "/dev/stune/top-app/schedtune.boost"
John Stultz0e785a22017-05-23 13:01:56 -070042#define SCHEDTUNE_BOOST_VAL_PROP "ro.config.schetune.touchboost.value"
43#define SCHEDTUNE_BOOST_TIME_PROP "ro.config.schetune.touchboost.time_ns"
44
45#define SCHEDTUNE_BOOST_VAL_DEFAULT "40"
46
47char schedtune_boost_norm[PROPERTY_VALUE_MAX] = "10";
48char schedtune_boost_interactive[PROPERTY_VALUE_MAX] = SCHEDTUNE_BOOST_VAL_DEFAULT;
49long long schedtune_boost_time_ns = 1000000000LL;
50
Leo Yanf0e78bf2017-11-28 22:01:58 +080051#define DEVFREQ_DDR_MIN_FREQ_PATH_PROP \
52 "ro.config.devfreq.ddr.min_freq.path"
53#define DEVFREQ_DDR_MIN_FREQ_BOOST_PROP \
54 "ro.config.devfreq.ddr.min_freq.boost"
55
56char devfreq_ddr_min_path[PROPERTY_VALUE_MAX];
57char devfreq_ddr_min_orig[PROPERTY_VALUE_MAX];
58char devfreq_ddr_min_boost[PROPERTY_VALUE_MAX];
59
60#define DEVFREQ_GPU_MIN_FREQ_PATH_PROP \
61 "ro.config.devfreq.gpu.min_freq.path"
62#define DEVFREQ_GPU_MIN_FREQ_BOOST_PROP \
63 "ro.config.devfreq.gpu.min_freq.boost"
64
65char devfreq_gpu_min_path[PROPERTY_VALUE_MAX];
66char devfreq_gpu_min_orig[PROPERTY_VALUE_MAX];
67char devfreq_gpu_min_boost[PROPERTY_VALUE_MAX];
68
John Stultz127e1cc2016-08-18 12:20:40 -070069#define INTERACTIVE_BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
70#define INTERACTIVE_IO_IS_BUSY_PATH "/sys/devices/system/cpu/cpufreq/interactive/io_is_busy"
John Stultz7266c5f2016-06-09 14:18:57 -070071
72struct hikey_power_module {
73 struct power_module base;
74 pthread_mutex_t lock;
John Stultz4c1a82b2016-08-18 14:49:01 -070075 /* interactive gov boost values */
John Stultz7266c5f2016-06-09 14:18:57 -070076 int boostpulse_fd;
77 int boostpulse_warned;
John Stultz4c1a82b2016-08-18 14:49:01 -070078 /* EAS schedtune values */
79 int schedtune_boost_fd;
80 long long deboost_time;
81 sem_t signal_lock;
John Stultz7266c5f2016-06-09 14:18:57 -070082};
83
John Stultzc1875b52018-11-20 16:15:20 -080084struct hikey_power_module this_power_module;
85
John Stultzed771732017-05-23 17:39:53 -070086
John Stultz7266c5f2016-06-09 14:18:57 -070087static bool low_power_mode = false;
88
John Stultzed771732017-05-23 17:39:53 -070089
90#define CPUFREQ_CLUST_MAX_FREQ_PATH_PROP "ro.config.cpufreq.max_freq.cluster"
91#define CPUFREQ_CLUST_LOW_POWER_MAX_FREQ_PROP "ro.config.cpufreq.low_power_max.cluster"
92#define CPUFREQ_CLUST0_MAX_FREQ_PATH_DEFAULT "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
93
94#define NR_CLUSTERS 4
95static int max_clusters = 1;
96static struct hikey_cpufreq_t {
97 char path[PROPERTY_VALUE_MAX];
98 char normal_max[PROPERTY_VALUE_MAX];
99 char low_power_max[PROPERTY_VALUE_MAX];
100} hikey_cpufreq_clusters[NR_CLUSTERS];
John Stultz7266c5f2016-06-09 14:18:57 -0700101
John Stultze150ab32016-08-18 14:04:34 -0700102#define container_of(addr, struct_name, field_name) \
103 ((struct_name *)((char *)(addr) - offsetof(struct_name, field_name)))
104
105
Dmitry Shmidtcc147582016-11-07 13:13:34 -0800106static int sysfs_write(const char *path, char *s)
John Stultz7266c5f2016-06-09 14:18:57 -0700107{
108 char buf[80];
109 int len;
110 int fd = open(path, O_WRONLY);
111
112 if (fd < 0) {
113 strerror_r(errno, buf, sizeof(buf));
114 ALOGE("Error opening %s: %s\n", path, buf);
Dmitry Shmidtcc147582016-11-07 13:13:34 -0800115 return fd;
John Stultz7266c5f2016-06-09 14:18:57 -0700116 }
117
118 len = write(fd, s, strlen(s));
119 if (len < 0) {
120 strerror_r(errno, buf, sizeof(buf));
121 ALOGE("Error writing to %s: %s\n", path, buf);
122 }
123
124 close(fd);
Dmitry Shmidtcc147582016-11-07 13:13:34 -0800125 return len;
John Stultz7266c5f2016-06-09 14:18:57 -0700126}
127
John Stultzed771732017-05-23 17:39:53 -0700128static int sysfs_read(const char *path, char *s, int slen)
129{
130 int len;
131 int fd = open(path, O_RDONLY);
132
133 if (fd < 0) {
134 ALOGE("Error opening %s\n", path);
135 return fd;
136 }
137
138 len = read(fd, s, slen);
139 if (len < 0) {
140 ALOGE("Error reading %s\n", path);
141 }
142
143 close(fd);
144 return len;
145}
146
John Stultz4c1a82b2016-08-18 14:49:01 -0700147#define NSEC_PER_SEC 1000000000LL
148static long long gettime_ns(void)
149{
150 struct timespec ts;
151
152 clock_gettime(CLOCK_MONOTONIC, &ts);
153 return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
154}
155
156static void nanosleep_ns(long long ns)
157{
158 struct timespec ts;
159 ts.tv_sec = ns/NSEC_PER_SEC;
160 ts.tv_nsec = ns%NSEC_PER_SEC;
161 nanosleep(&ts, NULL);
162}
163
John Stultzc5793712016-08-18 14:00:49 -0700164/*[interactive cpufreq gov funcs]*********************************************/
John Stultze150ab32016-08-18 14:04:34 -0700165static void interactive_power_init(struct hikey_power_module __unused *hikey)
John Stultz7266c5f2016-06-09 14:18:57 -0700166{
Dmitry Shmidtcc147582016-11-07 13:13:34 -0800167 if (sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
168 "20000") < 0)
169 return;
John Stultz7266c5f2016-06-09 14:18:57 -0700170 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_slack",
171 "20000");
172 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time",
173 "80000");
174 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq",
175 "1200000");
176 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load",
177 "99");
178 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads",
179 "65 729000:75 960000:85");
180 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay",
181 "20000");
182 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration",
183 "1000000");
184 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/io_is_busy", "0");
185
John Stultz7266c5f2016-06-09 14:18:57 -0700186}
187
John Stultz5e1546b2016-08-18 11:56:31 -0700188static int interactive_boostpulse(struct hikey_power_module *hikey)
189{
190 char buf[80];
191 int len;
192
John Stultz64b54ca2016-08-18 15:01:33 -0700193 if (hikey->boostpulse_fd < 0)
John Stultz127e1cc2016-08-18 12:20:40 -0700194 hikey->boostpulse_fd = open(INTERACTIVE_BOOSTPULSE_PATH, O_WRONLY);
John Stultz5e1546b2016-08-18 11:56:31 -0700195
John Stultz64b54ca2016-08-18 15:01:33 -0700196 if (hikey->boostpulse_fd < 0) {
197 if (!hikey->boostpulse_warned) {
John Stultz5e1546b2016-08-18 11:56:31 -0700198 strerror_r(errno, buf, sizeof(buf));
John Stultz127e1cc2016-08-18 12:20:40 -0700199 ALOGE("Error opening %s: %s\n", INTERACTIVE_BOOSTPULSE_PATH,
John Stultz64b54ca2016-08-18 15:01:33 -0700200 buf);
201 hikey->boostpulse_warned = 1;
John Stultz5e1546b2016-08-18 11:56:31 -0700202 }
John Stultz64b54ca2016-08-18 15:01:33 -0700203 return hikey->boostpulse_fd;
204 }
205
206 len = write(hikey->boostpulse_fd, "1", 1);
207 if (len < 0) {
208 strerror_r(errno, buf, sizeof(buf));
209 ALOGE("Error writing to %s: %s\n",
John Stultz127e1cc2016-08-18 12:20:40 -0700210 INTERACTIVE_BOOSTPULSE_PATH, buf);
John Stultz64b54ca2016-08-18 15:01:33 -0700211 return -1;
John Stultz5e1546b2016-08-18 11:56:31 -0700212 }
213 return 0;
214}
215
Leo Yanf0e78bf2017-11-28 22:01:58 +0800216static void
217hikey_devfreq_set_interactive(struct hikey_power_module __unused *hikey, int on)
218{
219 if (!on || low_power_mode) {
220 if (devfreq_ddr_min_path[0] != '\0')
221 sysfs_write(devfreq_ddr_min_path, devfreq_ddr_min_orig);
222
223 if (devfreq_gpu_min_path[0] != '\0')
224 sysfs_write(devfreq_gpu_min_path, devfreq_gpu_min_orig);
225 } else {
226 if (devfreq_ddr_min_path[0] != '\0')
227 sysfs_write(devfreq_ddr_min_path, devfreq_ddr_min_boost);
228
229 if (devfreq_gpu_min_path[0] != '\0')
230 sysfs_write(devfreq_gpu_min_path, devfreq_gpu_min_boost);
231 }
232}
233
234static void hikey_devfreq_init(struct hikey_power_module __unused *hikey)
235{
236 property_get(DEVFREQ_DDR_MIN_FREQ_PATH_PROP, devfreq_ddr_min_path, "");
237 if (devfreq_ddr_min_path[0] != '\0') {
238 sysfs_read(devfreq_ddr_min_path, devfreq_ddr_min_orig,
239 PROPERTY_VALUE_MAX);
240 property_get(DEVFREQ_DDR_MIN_FREQ_BOOST_PROP,
241 devfreq_ddr_min_boost, "");
242 }
243
244 property_get(DEVFREQ_GPU_MIN_FREQ_PATH_PROP, devfreq_gpu_min_path, "");
245 if (devfreq_gpu_min_path[0] != '\0') {
246 sysfs_read(devfreq_gpu_min_path, devfreq_gpu_min_orig,
247 PROPERTY_VALUE_MAX);
248 property_get(DEVFREQ_GPU_MIN_FREQ_BOOST_PROP,
249 devfreq_gpu_min_boost, "");
250 }
251}
252
John Stultz4c1a82b2016-08-18 14:49:01 -0700253/*[schedtune functions]*******************************************************/
John Stultzc5793712016-08-18 14:00:49 -0700254
John Stultzc1875b52018-11-20 16:15:20 -0800255static int schedtune_sysfs_boost(struct hikey_power_module *hikey, char* booststr)
John Stultz4c1a82b2016-08-18 14:49:01 -0700256{
257 char buf[80];
258 int len;
259
260 if (hikey->schedtune_boost_fd < 0)
261 return hikey->schedtune_boost_fd;
262
John Stultz0e785a22017-05-23 13:01:56 -0700263 len = write(hikey->schedtune_boost_fd, booststr, strlen(booststr));
John Stultz4c1a82b2016-08-18 14:49:01 -0700264 if (len < 0) {
265 strerror_r(errno, buf, sizeof(buf));
266 ALOGE("Error writing to %s: %s\n", SCHEDTUNE_BOOST_PATH, buf);
267 }
268 return len;
269}
270
271static void* schedtune_deboost_thread(void* arg)
272{
273 struct hikey_power_module *hikey = (struct hikey_power_module *)arg;
274
275 while(1) {
276 sem_wait(&hikey->signal_lock);
277 while(1) {
278 long long now, sleeptime = 0;
279
280 pthread_mutex_lock(&hikey->lock);
281 now = gettime_ns();
282 if (hikey->deboost_time > now) {
283 sleeptime = hikey->deboost_time - now;
284 pthread_mutex_unlock(&hikey->lock);
285 nanosleep_ns(sleeptime);
286 continue;
287 }
288
John Stultz0e785a22017-05-23 13:01:56 -0700289 schedtune_sysfs_boost(hikey, schedtune_boost_norm);
Leo Yanf0e78bf2017-11-28 22:01:58 +0800290 hikey_devfreq_set_interactive(hikey, 0);
John Stultz4c1a82b2016-08-18 14:49:01 -0700291 hikey->deboost_time = 0;
292 pthread_mutex_unlock(&hikey->lock);
293 break;
294 }
295 }
296 return NULL;
297}
298
299static int schedtune_boost(struct hikey_power_module *hikey)
300{
301 long long now;
302
303 if (hikey->schedtune_boost_fd < 0)
304 return hikey->schedtune_boost_fd;
305
306 now = gettime_ns();
307 if (!hikey->deboost_time) {
John Stultz0e785a22017-05-23 13:01:56 -0700308 schedtune_sysfs_boost(hikey, schedtune_boost_interactive);
Leo Yanf0e78bf2017-11-28 22:01:58 +0800309 hikey_devfreq_set_interactive(hikey, 1);
John Stultz4c1a82b2016-08-18 14:49:01 -0700310 sem_post(&hikey->signal_lock);
311 }
John Stultz0e785a22017-05-23 13:01:56 -0700312 hikey->deboost_time = now + schedtune_boost_time_ns;
John Stultz4c1a82b2016-08-18 14:49:01 -0700313
314 return 0;
315}
316
317static void schedtune_power_init(struct hikey_power_module *hikey)
318{
319 char buf[50];
320 pthread_t tid;
321
John Stultz4c1a82b2016-08-18 14:49:01 -0700322 hikey->deboost_time = 0;
323 sem_init(&hikey->signal_lock, 0, 1);
324
John Stultz0e785a22017-05-23 13:01:56 -0700325 hikey->schedtune_boost_fd = open(SCHEDTUNE_BOOST_PATH, O_RDWR);
John Stultz4c1a82b2016-08-18 14:49:01 -0700326 if (hikey->schedtune_boost_fd < 0) {
327 strerror_r(errno, buf, sizeof(buf));
328 ALOGE("Error opening %s: %s\n", SCHEDTUNE_BOOST_PATH, buf);
John Stultz0e785a22017-05-23 13:01:56 -0700329 return;
John Stultz4c1a82b2016-08-18 14:49:01 -0700330 }
331
John Stultz0e785a22017-05-23 13:01:56 -0700332 schedtune_boost_time_ns = property_get_int64(SCHEDTUNE_BOOST_TIME_PROP,
333 1000000000LL);
334 property_get(SCHEDTUNE_BOOST_VAL_PROP, schedtune_boost_interactive,
335 SCHEDTUNE_BOOST_VAL_DEFAULT);
336
337 if (hikey->schedtune_boost_fd >= 0) {
338 size_t len = read(hikey->schedtune_boost_fd, schedtune_boost_norm,
339 PROPERTY_VALUE_MAX);
340 if (len <= 0)
341 ALOGE("Error reading normal boost value\n");
342 else if (schedtune_boost_norm[len] == '\n')
343 schedtune_boost_norm[len] = '\0';
344
345 }
346
347 ALOGV("Starting with schedtune boost norm: %s touchboost: %s and boosttime: %lld\n",
348 schedtune_boost_norm, schedtune_boost_interactive, schedtune_boost_time_ns);
349
John Stultz4c1a82b2016-08-18 14:49:01 -0700350 pthread_create(&tid, NULL, schedtune_deboost_thread, hikey);
351}
352
353/*[generic functions]*********************************************************/
John Stultzed771732017-05-23 17:39:53 -0700354
John Stultzc1875b52018-11-20 16:15:20 -0800355void power_set_interactive(int on)
John Stultzed771732017-05-23 17:39:53 -0700356{
357 int i;
358
359 /*
360 * Lower maximum frequency when screen is off.
361 */
362 for (i=0; i < max_clusters; i++) {
363 if ((!on || low_power_mode) && hikey_cpufreq_clusters[i].low_power_max[0] != '\0')
364 sysfs_write(hikey_cpufreq_clusters[i].path, hikey_cpufreq_clusters[i].low_power_max);
365 else
366 sysfs_write(hikey_cpufreq_clusters[i].path, hikey_cpufreq_clusters[i].normal_max);
367 }
368 sysfs_write(INTERACTIVE_IO_IS_BUSY_PATH, on ? "1" : "0");
369}
370
371
Dmitry Shmidtb4db15e2017-10-24 16:02:26 -0700372static void hikey_cpufreq_init(struct hikey_power_module __unused *hikey)
John Stultzed771732017-05-23 17:39:53 -0700373{
374 char buf[128];
375 int len, i;
376
377 for (i=0; i < NR_CLUSTERS; i++) {
378 sprintf(buf,"%s%d", CPUFREQ_CLUST_MAX_FREQ_PATH_PROP, i);
379 property_get(buf, hikey_cpufreq_clusters[i].path, "");
380
381 if (hikey_cpufreq_clusters[i].path[0] == '\0') {
382 if (i == 0) {
383 /* In case no property was set, pick cpu0's cluster */
384 strncpy(hikey_cpufreq_clusters[i].path,
385 CPUFREQ_CLUST0_MAX_FREQ_PATH_DEFAULT,
386 PROPERTY_VALUE_MAX);
387 } else
388 break;
389 }
390 sprintf(buf,"%s%d", CPUFREQ_CLUST_LOW_POWER_MAX_FREQ_PROP, i);
391 property_get(buf, hikey_cpufreq_clusters[i].low_power_max, "");
392 len = sysfs_read(hikey_cpufreq_clusters[i].path,
393 hikey_cpufreq_clusters[i].normal_max,
394 PROPERTY_VALUE_MAX);
395 ALOGV("Cluster: %d path: %s low: %s norm: %s\n", i,
396 hikey_cpufreq_clusters[i].path,
397 hikey_cpufreq_clusters[i].low_power_max,
398 hikey_cpufreq_clusters[i].normal_max);
399 }
400 max_clusters = i;
401}
402
John Stultzc1875b52018-11-20 16:15:20 -0800403void power_init(void)
John Stultzc5793712016-08-18 14:00:49 -0700404{
John Stultzc1875b52018-11-20 16:15:20 -0800405 struct hikey_power_module *hikey = &this_power_module;
406 memset(hikey, 0, sizeof(struct hikey_power_module));
407 pthread_mutex_init(&hikey->lock, NULL);
408 hikey->boostpulse_fd = -1;
409 hikey->boostpulse_warned = 0;
410
John Stultzed771732017-05-23 17:39:53 -0700411 hikey_cpufreq_init(hikey);
Leo Yanf0e78bf2017-11-28 22:01:58 +0800412 hikey_devfreq_init(hikey);
John Stultze150ab32016-08-18 14:04:34 -0700413 interactive_power_init(hikey);
John Stultz4c1a82b2016-08-18 14:49:01 -0700414 schedtune_power_init(hikey);
415}
416
417static void hikey_hint_interaction(struct hikey_power_module *mod)
418{
419 /* Try interactive cpufreq boosting first */
420 if(!interactive_boostpulse(mod))
421 return;
422 /* Then try EAS schedtune boosting */
423 if(!schedtune_boost(mod))
424 return;
John Stultzc5793712016-08-18 14:00:49 -0700425}
426
John Stultzc1875b52018-11-20 16:15:20 -0800427void power_hint(power_hint_t hint, void *data)
John Stultz7266c5f2016-06-09 14:18:57 -0700428{
John Stultzc1875b52018-11-20 16:15:20 -0800429 struct hikey_power_module *hikey = &this_power_module;
John Stultz7266c5f2016-06-09 14:18:57 -0700430
431 pthread_mutex_lock(&hikey->lock);
432 switch (hint) {
433 case POWER_HINT_INTERACTION:
John Stultz4c1a82b2016-08-18 14:49:01 -0700434 hikey_hint_interaction(hikey);
John Stultz7266c5f2016-06-09 14:18:57 -0700435 break;
436
437 case POWER_HINT_VSYNC:
438 break;
439
440 case POWER_HINT_LOW_POWER:
John Stultz7266c5f2016-06-09 14:18:57 -0700441 low_power_mode = data;
John Stultzc1875b52018-11-20 16:15:20 -0800442 power_set_interactive(1);
John Stultz7266c5f2016-06-09 14:18:57 -0700443 break;
444
445 default:
446 break;
447 }
448 pthread_mutex_unlock(&hikey->lock);
449}