blob: 68899abd886be3b8cd7455bc9029190aa83f868c [file] [log] [blame]
Aaron Klingb2b3dd02015-11-12 09:25:04 -06001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved.
4 * Copyright (C) 2015 The CyanogenMod Project
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#define LOG_TAG "powerHAL::common"
18
19#include <hardware/hardware.h>
20#include <hardware/power.h>
21
22#include "powerhal_utils.h"
23#include "powerhal.h"
24
25#ifdef POWER_MODE_SET_INTERACTIVE
26static int get_system_power_mode(void);
27static void set_interactive_governor(int mode);
28
29static const interactive_data_t interactive_data_array[] =
30{
31 { "1122000", "65 304000:75 1122000:80", "19000", "20000", "0", "41000", "90" },
Aaron Kling5d3e0ed2016-01-21 09:26:58 -060032 { "1020000", "65 256000:75 1020000:80", "19000", "20000", "0", "30000", "99" },
Aaron Klingb2b3dd02015-11-12 09:25:04 -060033 { "640000", "65 256000:75 640000:80", "80000", "20000", "2", "30000", "99" },
Aaron Kling5d3e0ed2016-01-21 09:26:58 -060034 { "1020002", "65 256000:75 1020000:80", "19000", "20000", "0", "30000", "99" },
Aaron Klingb2b3dd02015-11-12 09:25:04 -060035 { "420000", "80", "80000", "300000","2", "30000", "99" }
36};
37#endif
38
Aaron Kling5d3e0ed2016-01-21 09:26:58 -060039static const int VSyncActiveBoostFreq = 300000;
Aaron Klingb2b3dd02015-11-12 09:25:04 -060040static int uC_input_number = 1;
41
42/*static void set_led_state(int on)
43{
44 struct input_event ev_out;
45 int len;
46 char buf[80];
47 int size;
48 int fd;
49 bool breathe = get_property_bool(LED_BREATHE_PROP, true);
50 char path[20];
51
52 size = sizeof(struct input_event);
53 on = (on == 0)?0:1;
54 snprintf(path, sizeof(path), "/dev/input/event%d", uC_input_number);
55
56 fd = open(path, O_WRONLY);
57 if (fd < 0) {
58 strerror_r(errno, buf, sizeof(buf));
59 ALOGE("Error opening %s: %s\n", path, buf);
60 return;
61 }
62
63 ev_out.type = EV_LED;
64 if (on == 1) {
65 ev_out.code = LED_CAPSL;
66 } else {
67 if (breathe == true)
68 ev_out.code = LED_SCROLLL;
69 else
70 ev_out.code = LED_COMPOSE;
71 }
72 ev_out.value = 1;
73
74 len = write(fd, &ev_out, size);
75 usleep(10000);
76
77 if (len < 0) {
78 strerror_r(errno, buf, sizeof(buf));
79 ALOGE("Error writing to %s: %s\n", path, buf);
80 }
81
82 ev_out.value = 0;
83
84 len = write(fd, &ev_out, size);
85 usleep(10000);
86
87 if (len < 0) {
88 strerror_r(errno, buf, sizeof(buf));
89 ALOGE("Error writing to %s: %s\n", path, buf);
90 }
91 close(fd);
92}*/
93
94static int get_input_count(void)
95{
96 int i = 0;
97 int ret;
98 char path[80];
99 char name[50];
100
101 while(1)
102 {
103 snprintf(path, sizeof(path), "/sys/class/input/input%d/name", i);
104 ret = access(path, F_OK);
105 if (ret < 0)
106 break;
107 memset(name, 0, 50);
108 sysfs_read(path, name, 50);
109 if (0 == strcmp(name, "NVIDIA Corporation NVIDIA Controller v01.01\n"))
110 uC_input_number = i;
111 ALOGI("input device id:%d present with name:%s", i++, name);
112 }
113 return i;
114}
115
116static void find_input_device_ids(struct powerhal_info *pInfo)
117{
118 int i = 0;
119 int status;
120 int count = 0;
121 char path[80];
122 char name[MAX_CHARS];
123
124 while (1)
125 {
126 snprintf(path, sizeof(path), "/sys/class/input/input%d/name", i);
127 if (access(path, F_OK) < 0)
128 break;
129 else {
130 memset(name, 0, MAX_CHARS);
131 sysfs_read(path, name, MAX_CHARS);
132 for (int j = 0; j < pInfo->input_cnt; j++) {
133 status = (-1 == pInfo->input_devs[j].dev_id)
134 && (0 == strncmp(name,
135 pInfo->input_devs[j].dev_name, MAX_CHARS));
136 if (status) {
137 ++count;
138 pInfo->input_devs[j].dev_id = i;
139 ALOGI("find_input_device_ids: %d %s",
140 pInfo->input_devs[j].dev_id,
141 pInfo->input_devs[j].dev_name);
142 }
143 }
144 ++i;
145 }
146
147 if (count == pInfo->input_cnt)
148 break;
149 }
150}
151
152static int check_hint(struct powerhal_info *pInfo, power_hint_t hint, uint64_t *t)
153{
154 struct timespec ts;
155 uint64_t time;
156
157 if (hint >= MAX_POWER_HINT_COUNT) {
158 ALOGE("Invalid power hint: 0x%x", hint);
159 return -1;
160 }
161
162 clock_gettime(CLOCK_MONOTONIC, &ts);
163 time = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
164
165 if (pInfo->hint_time[hint] && pInfo->hint_interval[hint] &&
166 (time - pInfo->hint_time[hint] < pInfo->hint_interval[hint]))
167 return -1;
168
169 *t = time;
170
171 return 0;
172}
173
174static bool is_available_frequency(struct powerhal_info *pInfo, int freq)
175{
176 int i;
177
178 for(i = 0; i < pInfo->num_available_frequencies; i++) {
179 if(pInfo->available_frequencies[i] == freq)
180 return true;
181 }
182
183 return false;
184}
185
186void common_power_open(struct powerhal_info *pInfo)
187{
188 int i;
189 int size = 256;
190 char *pch;
191
192 if (0 == pInfo->input_devs || 0 == pInfo->input_cnt)
193 pInfo->input_cnt = get_input_count();
194 else
195 find_input_device_ids(pInfo);
196
197 // Initialize timeout poker
198 Barrier readyToRun;
199 pInfo->mTimeoutPoker = new TimeoutPoker(&readyToRun);
200 readyToRun.wait();
201
202 // Read available frequencies
203 char *buf = (char*)malloc(sizeof(char) * size);
204 memset(buf, 0, size);
205 sysfs_read("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies",
206 buf, size);
207
208 // Determine number of available frequencies
209 pch = strtok(buf, " ");
210 pInfo->num_available_frequencies = -1;
211 while(pch != NULL)
212 {
213 pch = strtok(NULL, " ");
214 pInfo->num_available_frequencies++;
215 }
216
217 // Store available frequencies in a lookup array
218 pInfo->available_frequencies = (int*)malloc(sizeof(int) * pInfo->num_available_frequencies);
219 sysfs_read("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies",
220 buf, size);
221 pch = strtok(buf, " ");
222 for(i = 0; i < pInfo->num_available_frequencies; i++)
223 {
224 pInfo->available_frequencies[i] = atoi(pch);
225 pch = strtok(NULL, " ");
226 }
227
228 // Store LP cluster max frequency
229 sysfs_read("/sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/idle_top_freq",
230 buf, size);
231 pInfo->lp_max_frequency = atoi(buf);
232
233 pInfo->interaction_boost_frequency = pInfo->lp_max_frequency;
234 pInfo->animation_boost_frequency = pInfo->lp_max_frequency;
235
236 for (i = 0; i < pInfo->num_available_frequencies; i++)
237 {
238 if (pInfo->available_frequencies[i] >= 1326000) {
239 pInfo->interaction_boost_frequency = pInfo->available_frequencies[i];
240 break;
241 }
242 }
243
244 for (i = 0; i < pInfo->num_available_frequencies; i++)
245 {
246 if (pInfo->available_frequencies[i] >= 1024000) {
247 pInfo->animation_boost_frequency = pInfo->available_frequencies[i];
248 break;
249 }
250 }
251
252 // Store CPU0 max frequency
253 sysfs_read(SYS_NODE_CPU0_MAX_FREQ, buf, size);
254 pInfo->cpu0_max_frequency = atoi(buf);
255
256 // Initialize hint intervals in usec
257 //
258 // Set the interaction timeout to be slightly shorter than the duration of
259 // the interaction boost so that we can maintain is constantly during
260 // interaction.
261 pInfo->hint_interval[POWER_HINT_INTERACTION] = 90000;
Joel Maxuelb2e304f2016-01-24 15:27:57 -0400262 //pInfo->hint_interval[POWER_HINT_CPU_BOOST] = 500000;
263 //pInfo->hint_interval[POWER_HINT_AUDIO] = 500000;
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600264 pInfo->hint_interval[POWER_HINT_LOW_POWER] = 0;
265
266 // Initialize features
267 pInfo->features.fan = sysfs_exists("/sys/devices/platform/pwm-fan/pwm_cap");
268
269 free(buf);
270}
271
Aaron Kling5d3e0ed2016-01-21 09:26:58 -0600272static void set_vsync_min_cpu_freq(struct powerhal_info *pInfo, int enabled)
273{
274 static int vsync_min_cpu = -1;
275
276 if (enabled && vsync_min_cpu == -1) {
277 vsync_min_cpu =
278 pInfo->mTimeoutPoker->requestPmQos(PMQOS_CONSTRAINT_CPU_FREQ, PM_QOS_BOOST_PRIORITY, PM_QOS_DEFAULT_VALUE, VSyncActiveBoostFreq);
279 } else if (!enabled && vsync_min_cpu >= 0) {
280 close(vsync_min_cpu);
281 vsync_min_cpu = -1;
282 }
283
284 ALOGV("%s: set min CPU floor =%i", __func__, VSyncActiveBoostFreq);
285}
286
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600287static void set_fan_cap(struct powerhal_info *pInfo, int value)
288{
289 if (!pInfo->features.fan)
290 return;
291
292 if (value < 0)
293 value = 70;
294
295 sysfs_write_int("/sys/devices/platform/pwm-fan/pwm_cap", value);
296}
297
298static void set_affinity_daemon_enable(__attribute__ ((unused)) struct powerhal_info *pInfo, int value)
299{
300 if (value == 1)
301 set_property_int(AFFINITY_DAEMON_CONTROL_PROP, 1);
302 else
303 set_property_int(AFFINITY_DAEMON_CONTROL_PROP, 0);
304 ALOGV("%s: set affinity daemon enable =%d", __func__, value);
305}
306
307void common_power_init(__attribute__ ((unused)) struct power_module *module, struct powerhal_info *pInfo)
308{
309 common_power_open(pInfo);
310
311 pInfo->ftrace_enable = get_property_bool("nvidia.hwc.ftrace_enable", false);
312
313 // Boost to max frequency on initialization to decrease boot time
314 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_CPU_FREQ,
315 PM_QOS_BOOST_PRIORITY,
316 PM_QOS_DEFAULT_VALUE,
317 pInfo->available_frequencies[pInfo->num_available_frequencies - 1],
318 s2ns(15));
319}
320
321void common_power_set_interactive(__attribute__ ((unused)) struct power_module *module, struct powerhal_info *pInfo, int on)
322{
323 int i;
324 int dev_id;
325 char path[80];
326 const char* state = (0 == on)?"0":"1";
Aaron Kling5d3e0ed2016-01-21 09:26:58 -0600327 int power_mode = -1;
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600328
329 sysfs_write("/sys/devices/platform/host1x/nvavp/boost_sclk", state);
330
331 if (0 != pInfo) {
332 for (i = 0; i < pInfo->input_cnt; i++) {
333 if (0 == pInfo->input_devs)
334 dev_id = i;
335 else if (-1 == pInfo->input_devs[i].dev_id)
336 continue;
337 else
338 dev_id = pInfo->input_devs[i].dev_id;
339 snprintf(path, sizeof(path), "/sys/class/input/input%d/enabled", dev_id);
340 if (!access(path, W_OK)) {
341 if (0 == on)
342 ALOGI("Disabling input device:%d", dev_id);
343 else
344 ALOGI("Enabling input device:%d", dev_id);
345 sysfs_write(path, state);
346 }
347 }
348 }
349
350#ifdef POWER_MODE_SET_INTERACTIVE // Tegra X1
351 if (on) {
352 power_mode = get_system_power_mode();
Aaron Kling3e793d02016-06-26 22:43:09 -0500353 if (power_mode < 0 || power_mode >= sizeof(interactive_data_array)/sizeof(interactive_data_array[0])) {
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600354 ALOGV("%s: no system power mode info, take optimized settings", __func__);
355 power_mode = 0;
356 }
357 } else {
358 power_mode = sizeof(interactive_data_array)/sizeof(interactive_data_array[0]);
359 }
360 set_interactive_governor(power_mode);
361#elif defined(POWER_MODE_LEGACY) // Tegra 4
362 sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
363 (on == 0)?"conservative":"interactive");
364#else // Tegra K1
365 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq", (on == 0)?"420000":"624000");
366 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads", (on == 0)?"45 312000:75 564000:85":"65 228000:75 624000:85");
367 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay", (on == 0)?"80000":"19000");
368 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate", (on == 0)?"300000":"20000");
369 sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boost_factor", (on == 0)?"2":"0");
370#endif
371}
372
373#ifdef POWER_MODE_SET_INTERACTIVE
374static int get_system_power_mode(void)
375{
376 char value[PROPERTY_VALUE_MAX] = { 0 };
377 int power_mode = -1;
378
379 property_get("persist.sys.NV_POWER_MODE", value, "");
380 if (value[0] != '\0')
381 {
382 power_mode = atoi(value);
383 }
384
385 if (get_property_bool("persist.sys.NV_ECO.STATE.ISECO", false))
386 {
387 power_mode = 2;
388 }
389
390 return power_mode;
391}
392
393static void __sysfs_write(const char *file, const char *data)
394{
395 if (data != NULL)
396 {
397 sysfs_write(file, data);
398 }
399}
400
401static void set_interactive_governor(int mode)
402{
403 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/hispeed_freq",
404 interactive_data_array[mode].hispeed_freq);
405 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/target_loads",
406 interactive_data_array[mode].target_loads);
407 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay",
408 interactive_data_array[mode].above_hispeed_delay);
409 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/timer_rate",
410 interactive_data_array[mode].timer_rate);
411 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boost_factor",
412 interactive_data_array[mode].boost_factor);
413 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/min_sample_time",
414 interactive_data_array[mode].min_sample_time);
415 __sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load",
416 interactive_data_array[mode].go_hispeed_load);
417}
418
419static void set_power_mode_hint(struct powerhal_info *pInfo, int mode)
420{
421 int status;
422 char value[4] = { 0 };
423
424 if (mode < 0 || mode > sizeof(interactive_data_array)/sizeof(interactive_data_array[0]))
425 {
426 ALOGE("%s: invalid hint mode = %d", __func__, mode);
427 return;
428 }
429
430 // only set interactive governor parameters when display on
431 sysfs_read("/sys/class/backlight/pwm-backlight/brightness", value, sizeof(value));
432 status = atoi(value);
433
434 if (status)
435 {
436 set_interactive_governor(mode);
437 }
438
439}
440#endif
441
442void common_power_hint(__attribute__ ((unused)) struct power_module *module, struct powerhal_info *pInfo,
443 power_hint_t hint, void *data)
444{
445 uint64_t t;
446
447 if (!pInfo)
448 return;
449
450 if (check_hint(pInfo, hint, &t) < 0)
451 return;
452
453 switch (hint) {
454 case POWER_HINT_VSYNC:
Aaron Kling5d3e0ed2016-01-21 09:26:58 -0600455 if (data)
456 set_vsync_min_cpu_freq(pInfo, *(int *)data);
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600457 break;
458 case POWER_HINT_INTERACTION:
459 if (pInfo->ftrace_enable) {
460 sysfs_write("/sys/kernel/debug/tracing/trace_marker", "Start POWER_HINT_INTERACTION\n");
461 }
462 // Boost to interaction_boost_frequency
463 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_CPU_FREQ,
464 PM_QOS_BOOST_PRIORITY,
465 PM_QOS_DEFAULT_VALUE,
466 pInfo->interaction_boost_frequency,
467 ms2ns(100));
468 // During the animation, we need some level of CPU/GPU/EMC frequency floor
469 // to get perfect animation. Forcing CPU frequency through PMQoS does not
470 // scale EMC fast enough so EMC frequency boosting should be placed first.
471 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_ONLINE_CPUS,
472 PM_QOS_BOOST_PRIORITY,
473 PM_QOS_DEFAULT_VALUE,
474 2,
475 s2ns(2));
476 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_CPU_FREQ,
477 PM_QOS_BOOST_PRIORITY,
478 PM_QOS_DEFAULT_VALUE,
479 pInfo->animation_boost_frequency,
480 s2ns(2));
481 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_GPU_FREQ,
482 PM_QOS_BOOST_PRIORITY,
483 PM_QOS_DEFAULT_VALUE,
Aaron Kling5d3e0ed2016-01-21 09:26:58 -0600484 540000,
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600485 s2ns(2));
486 pInfo->mTimeoutPoker->requestPmQosTimed("/dev/emc_freq_min",
487 396000,
488 s2ns(2));
489 break;
Joel Maxuelb2e304f2016-01-24 15:27:57 -0400490 //case POWER_HINT_CPU_BOOST:
491 // // Boost to 1.2Ghz dual core
492 // pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_CPU_FREQ,
493 // PM_QOS_BOOST_PRIORITY,
494 // PM_QOS_DEFAULT_VALUE,
495 // INT_MAX,
496 // ms2ns(1500));
497 // pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_ONLINE_CPUS,
498 // PM_QOS_BOOST_PRIORITY,
499 // PM_QOS_DEFAULT_VALUE,
500 // 2,
501 // ms2ns(1500));
502 // pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_GPU_FREQ,
503 // PM_QOS_BOOST_PRIORITY,
504 // PM_QOS_DEFAULT_VALUE,
505 // 180000,
506 // ms2ns(1500));
507 // pInfo->mTimeoutPoker->requestPmQosTimed("/dev/emc_freq_min",
508 // 792000,
509 // ms2ns(1500));
510 // break;
511 //case POWER_HINT_AUDIO:
512 // // Boost to 512 Mhz frequency for one second
513 // pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_CONSTRAINT_CPU_FREQ,
514 // PM_QOS_BOOST_PRIORITY,
515 // PM_QOS_DEFAULT_VALUE,
516 // 512000,
517 // s2ns(1));
518 // break;
Aaron Klingb2b3dd02015-11-12 09:25:04 -0600519 case POWER_HINT_LOW_POWER:
520#ifdef POWER_MODE_SET_INTERACTIVE
521 // Set interactive governor parameters according to power mode
522 // This is only partially using the functionality since aosp only has
523 // two power modes: normal and low power.
524 set_power_mode_hint(pInfo, (data ? 2 : 0));
525#else
526 // Drop max frequencies and limit to one core for low power mode
527 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_MAX_CPU_FREQ,
528 PM_QOS_BOOST_PRIORITY,
529 PM_QOS_DEFAULT_VALUE,
530 (data ? 1020000 : INT_MAX),
531 s2ns(1));
532 pInfo->mTimeoutPoker->requestPmQosTimed(PMQOS_MAX_ONLINE_CPUS,
533 PM_QOS_BOOST_PRIORITY,
534 PM_QOS_DEFAULT_VALUE,
535 (data ? 1 : INT_MAX),
536 s2ns(1));
537#endif
538 break;
539 default:
540 ALOGE("Unknown power hint: 0x%x", hint);
541 break;
542 }
543
544 pInfo->hint_time[hint] = t;
545}