1 /*
2 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #define LOG_NDEBUG 1
31
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <dlfcn.h>
39 #include <stdlib.h>
40
41 #define LOG_TAG "QCOM PowerHAL"
42 #include <utils/Log.h>
43 #include <hardware/hardware.h>
44 #include <hardware/power.h>
45 #include <cutils/properties.h>
46
47 #include "utils.h"
48 #include "metadata-defs.h"
49 #include "hint-data.h"
50 #include "performance.h"
51 #include "power-common.h"
52
53 #define USINSEC 1000000L
54 #define NSINUS 1000L
55
56 #define PLATFORM_SLEEP_MODES 2
57 #define XO_VOTERS 4
58 #define VMIN_VOTERS 0
59
60 #define RPM_PARAMETERS 4
61 #define NUM_PARAMETERS 12
62
63 #ifndef RPM_STAT
64 #define RPM_STAT "/d/rpm_stats"
65 #endif
66
67 #ifndef RPM_MASTER_STAT
68 #define RPM_MASTER_STAT "/d/rpm_master_stats"
69 #endif
70
71 /* RPM runs at 19.2Mhz. Divide by 19200 for msec */
72 #define RPM_CLK 19200
73
74 const char *parameter_names[] = {
75 "vlow_count",
76 "accumulated_vlow_time",
77 "vmin_count",
78 "accumulated_vmin_time",
79 "xo_accumulated_duration",
80 "xo_count",
81 "xo_accumulated_duration",
82 "xo_count",
83 "xo_accumulated_duration",
84 "xo_count",
85 "xo_accumulated_duration",
86 "xo_count"
87 };
88
89 static int saved_dcvs_cpu0_slack_max = -1;
90 static int saved_dcvs_cpu0_slack_min = -1;
91 static int saved_mpdecision_slack_max = -1;
92 static int saved_mpdecision_slack_min = -1;
93 static int saved_interactive_mode = -1;
94 static int slack_node_rw_failed = 0;
95 static int display_hint_sent;
96 int display_boost;
97 static int sustained_mode_handle = 0;
98 static int vr_mode_handle = 0;
99 int sustained_performance_mode = 0;
100 int vr_mode = 0;
101
102 //interaction boost global variables
103 static pthread_mutex_t s_interaction_lock = PTHREAD_MUTEX_INITIALIZER;
104 static struct timespec s_previous_boost_timespec;
105 static int s_previous_duration;
106
power_init(struct power_module * module)107 static void power_init(struct power_module *module)
108 {
109 ALOGV("QCOM power HAL initing.");
110
111 int fd;
112 char buf[10] = {0};
113
114 fd = open("/sys/devices/soc0/soc_id", O_RDONLY);
115 if (fd >= 0) {
116 if (read(fd, buf, sizeof(buf) - 1) == -1) {
117 ALOGW("Unable to read soc_id");
118 } else {
119 int soc_id = atoi(buf);
120 if (soc_id == 194 || (soc_id >= 208 && soc_id <= 218) || soc_id == 178) {
121 display_boost = 1;
122 }
123 }
124 close(fd);
125 }
126 }
127
process_video_decode_hint(void * metadata)128 static void process_video_decode_hint(void *metadata)
129 {
130 char governor[80];
131 struct video_decode_metadata_t video_decode_metadata;
132
133 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
134 ALOGE("Can't obtain scaling governor.");
135
136 return;
137 }
138
139 if (metadata) {
140 ALOGV("Processing video decode hint. Metadata: %s", (char *)metadata);
141 }
142
143 /* Initialize encode metadata struct fields. */
144 memset(&video_decode_metadata, 0, sizeof(struct video_decode_metadata_t));
145 video_decode_metadata.state = -1;
146 video_decode_metadata.hint_id = DEFAULT_VIDEO_DECODE_HINT_ID;
147
148 if (metadata) {
149 if (parse_video_decode_metadata((char *)metadata, &video_decode_metadata) ==
150 -1) {
151 ALOGE("Error occurred while parsing metadata.");
152 return;
153 }
154 } else {
155 return;
156 }
157
158 if (video_decode_metadata.state == 1) {
159 if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
160 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
161 int resource_values[] = {THREAD_MIGRATION_SYNC_OFF};
162
163 perform_hint_action(video_decode_metadata.hint_id,
164 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
165 } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
166 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
167 int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026, THREAD_MIGRATION_SYNC_OFF};
168
169 perform_hint_action(video_decode_metadata.hint_id,
170 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
171 }
172 } else if (video_decode_metadata.state == 0) {
173 if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
174 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
175 } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
176 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
177 undo_hint_action(video_decode_metadata.hint_id);
178 }
179 }
180 }
181
process_video_encode_hint(void * metadata)182 static void process_video_encode_hint(void *metadata)
183 {
184 char governor[80];
185 struct video_encode_metadata_t video_encode_metadata;
186
187 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
188 ALOGE("Can't obtain scaling governor.");
189
190 return;
191 }
192
193 /* Initialize encode metadata struct fields. */
194 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
195 video_encode_metadata.state = -1;
196 video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
197
198 if (metadata) {
199 if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) ==
200 -1) {
201 ALOGE("Error occurred while parsing metadata.");
202 return;
203 }
204 } else {
205 return;
206 }
207
208 if (video_encode_metadata.state == 1) {
209 if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
210 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
211 int resource_values[] = {IO_BUSY_OFF, SAMPLING_DOWN_FACTOR_1, THREAD_MIGRATION_SYNC_OFF};
212
213 perform_hint_action(video_encode_metadata.hint_id,
214 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
215 } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
216 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
217 int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026, THREAD_MIGRATION_SYNC_OFF,
218 INTERACTIVE_IO_BUSY_OFF};
219
220 perform_hint_action(video_encode_metadata.hint_id,
221 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
222 }
223 } else if (video_encode_metadata.state == 0) {
224 if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
225 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
226 undo_hint_action(video_encode_metadata.hint_id);
227 } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
228 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
229 undo_hint_action(video_encode_metadata.hint_id);
230 }
231 }
232 }
233
power_hint_override(struct power_module * module,power_hint_t hint,void * data)234 int __attribute__ ((weak)) power_hint_override(struct power_module *module, power_hint_t hint,
235 void *data)
236 {
237 return HINT_NONE;
238 }
239
240 /* Declare function before use */
241 void interaction(int duration, int num_args, int opt_list[]);
242 void release_request(int lock_handle);
243
calc_timespan_us(struct timespec start,struct timespec end)244 static long long calc_timespan_us(struct timespec start, struct timespec end) {
245 long long diff_in_us = 0;
246 diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
247 diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
248 return diff_in_us;
249 }
250
power_hint(struct power_module * module,power_hint_t hint,void * data)251 static void power_hint(struct power_module *module, power_hint_t hint,
252 void *data)
253 {
254 /* Check if this hint has been overridden. */
255 if (power_hint_override(module, hint, data) == HINT_HANDLED) {
256 /* The power_hint has been handled. We can skip the rest. */
257 return;
258 }
259
260 switch(hint) {
261 case POWER_HINT_VSYNC:
262 break;
263 /* Sustained performance mode:
264 * All CPUs are capped to ~1.2GHz
265 * GPU frequency is capped to 315MHz
266 */
267 /* VR+Sustained performance mode:
268 * All CPUs are locked to ~1.2GHz
269 * GPU frequency is locked to 315MHz
270 * GPU BW min_freq is raised to 775MHz
271 */
272 case POWER_HINT_SUSTAINED_PERFORMANCE:
273 {
274 int duration = 0;
275 pthread_mutex_lock(&s_interaction_lock);
276 if (data && sustained_performance_mode == 0) {
277 int* resources;
278 if (vr_mode == 0) { // Sustained mode only.
279 // Ensure that POWER_HINT_LAUNCH is not in progress.
280 if (launch_mode == 1) {
281 release_request(launch_handle);
282 launch_mode = 0;
283 }
284 // 0x40804000: cpu0 max freq
285 // 0x40804100: cpu2 max freq
286 // 0x42C20000: gpu max freq
287 // 0x42C24000: gpu min freq
288 // 0x42C28000: gpu bus min freq
289 int resources[] = {0x40804000, 1209, 0x40804100, 1209,
290 0x42C24000, 133, 0x42C20000, 315,
291 0x42C28000, 7759};
292 sustained_mode_handle = interaction_with_handle(
293 sustained_mode_handle, duration,
294 sizeof(resources) / sizeof(resources[0]), resources);
295 } else if (vr_mode == 1) { // Sustained + VR mode.
296 release_request(vr_mode_handle);
297 // 0x40804000: cpu0 max freq
298 // 0x40804100: cpu2 max freq
299 // 0x40800000: cpu0 min freq
300 // 0x40800100: cpu2 min freq
301 // 0x42C20000: gpu max freq
302 // 0x42C24000: gpu min freq
303 // 0x42C28000: gpu bus min freq
304 int resources[] = {0x40800000, 1209, 0x40800100, 1209,
305 0x40804000, 1209, 0x40804100, 1209,
306 0x42C24000, 315, 0x42C20000, 315,
307 0x42C28000, 7759};
308 sustained_mode_handle = interaction_with_handle(
309 sustained_mode_handle, duration,
310 sizeof(resources) / sizeof(resources[0]), resources);
311 }
312 sustained_performance_mode = 1;
313 } else if (sustained_performance_mode == 1) {
314 release_request(sustained_mode_handle);
315 if (vr_mode == 1) { // Switch back to VR Mode.
316 // 0x40804000: cpu0 max freq
317 // 0x40804100: cpu2 max freq
318 // 0x40800000: cpu0 min freq
319 // 0x40800100: cpu2 min freq
320 // 0x42C20000: gpu max freq
321 // 0x42C24000: gpu min freq
322 // 0x42C28000: gpu bus min freq
323 int resources[] = {0x40804000, 1440, 0x40804100, 1440,
324 0x40800000, 1440, 0x40800100, 1440,
325 0x42C20000, 510, 0x42C24000, 510,
326 0x42C28000, 7759};
327 vr_mode_handle = interaction_with_handle(
328 vr_mode_handle, duration,
329 sizeof(resources) / sizeof(resources[0]), resources);
330 }
331 sustained_performance_mode = 0;
332 }
333 pthread_mutex_unlock(&s_interaction_lock);
334 }
335 break;
336 /* VR mode:
337 * All CPUs are locked at ~1.4GHz
338 * GPU frequency is locked to 510MHz
339 * GPU BW min_freq is raised to 775MHz
340 */
341 case POWER_HINT_VR_MODE:
342 {
343 int duration = 0;
344 pthread_mutex_lock(&s_interaction_lock);
345 if (data && vr_mode == 0) {
346 if (sustained_performance_mode == 0) { // VR mode only.
347 // Ensure that POWER_HINT_LAUNCH is not in progress.
348 if (launch_mode == 1) {
349 release_request(launch_handle);
350 launch_mode = 0;
351 }
352 // 0x40804000: cpu0 max freq
353 // 0x40804100: cpu2 max freq
354 // 0x40800000: cpu0 min freq
355 // 0x40800100: cpu2 min freq
356 // 0x42C20000: gpu max freq
357 // 0x42C24000: gpu min freq
358 // 0x42C28000: gpu bus min freq
359 int resources[] = {0x40800000, 1440, 0x40800100, 1440,
360 0x40804000, 1440, 0x40804100, 1440,
361 0x42C20000, 510, 0x42C24000, 510,
362 0x42C28000, 7759};
363 vr_mode_handle = interaction_with_handle(
364 vr_mode_handle, duration,
365 sizeof(resources) / sizeof(resources[0]), resources);
366 } else if (sustained_performance_mode == 1) { // Sustained + VR mode.
367 release_request(sustained_mode_handle);
368 // 0x40804000: cpu0 max freq
369 // 0x40804100: cpu2 max freq
370 // 0x40800000: cpu0 min freq
371 // 0x40800100: cpu2 min freq
372 // 0x42C20000: gpu max freq
373 // 0x42C24000: gpu min freq
374 // 0x42C28000: gpu bus min freq
375 int resources[] = {0x40800000, 1209, 0x40800100, 1209,
376 0x40804000, 1209, 0x40804100, 1209,
377 0x42C24000, 315, 0x42C20000, 315,
378 0x42C28000, 7759};
379
380 vr_mode_handle = interaction_with_handle(
381 vr_mode_handle, duration,
382 sizeof(resources) / sizeof(resources[0]), resources);
383 }
384 vr_mode = 1;
385 } else if (vr_mode == 1) {
386 release_request(vr_mode_handle);
387 if (sustained_performance_mode == 1) { // Switch back to sustained Mode.
388 // 0x40804000: cpu0 max freq
389 // 0x40804100: cpu2 max freq
390 // 0x40800000: cpu0 min freq
391 // 0x40800100: cpu2 min freq
392 // 0x42C20000: gpu max freq
393 // 0x42C24000: gpu min freq
394 // 0x42C28000: gpu bus min freq
395 int resources[] = {0x40800000, 0, 0x40800100, 0,
396 0x40804000, 1209, 0x40804100, 1209,
397 0x42C24000, 133, 0x42C20000, 315,
398 0x42C28000, 0};
399 sustained_mode_handle = interaction_with_handle(
400 sustained_mode_handle, duration,
401 sizeof(resources) / sizeof(resources[0]), resources);
402 }
403 vr_mode = 0;
404 }
405 pthread_mutex_unlock(&s_interaction_lock);
406 }
407 break;
408 case POWER_HINT_INTERACTION:
409 {
410 char governor[80];
411
412 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
413 ALOGE("Can't obtain scaling governor.");
414 return;
415 }
416
417 pthread_mutex_lock(&s_interaction_lock);
418 if (sustained_performance_mode || vr_mode) {
419 pthread_mutex_unlock(&s_interaction_lock);
420 return;
421 }
422
423 int duration = 1500; // 1.5s by default
424 if (data) {
425 int input_duration = *((int*)data) + 750;
426 if (input_duration > duration) {
427 duration = (input_duration > 5750) ? 5750 : input_duration;
428 }
429 }
430
431 struct timespec cur_boost_timespec;
432 clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
433
434 long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
435 // don't hint if previous hint's duration covers this hint's duration
436 if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
437 pthread_mutex_unlock(&s_interaction_lock);
438 return;
439 }
440 s_previous_boost_timespec = cur_boost_timespec;
441 s_previous_duration = duration;
442
443 // Scheduler is EAS.
444 if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
445 // Setting the value of foreground schedtune boost to 50 and
446 // scaling_min_freq to 1100MHz.
447 int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
448 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
449 } else { // Scheduler is HMP.
450 int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
451 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
452 }
453 pthread_mutex_unlock(&s_interaction_lock);
454 }
455 break;
456 case POWER_HINT_VIDEO_ENCODE:
457 process_video_encode_hint(data);
458 break;
459 case POWER_HINT_VIDEO_DECODE:
460 process_video_decode_hint(data);
461 break;
462 default:
463 break;
464 }
465 }
466
set_interactive_override(struct power_module * module,int on)467 int __attribute__ ((weak)) set_interactive_override(struct power_module *module, int on)
468 {
469 return HINT_NONE;
470 }
471
set_interactive(struct power_module * module,int on)472 void set_interactive(struct power_module *module, int on)
473 {
474 char governor[80];
475 char tmp_str[NODE_MAX];
476 struct video_encode_metadata_t video_encode_metadata;
477 int rc = 0;
478
479 if (set_interactive_override(module, on) == HINT_HANDLED) {
480 return;
481 }
482
483 ALOGV("Got set_interactive hint");
484
485 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
486 ALOGE("Can't obtain scaling governor.");
487
488 return;
489 }
490
491 if (!on) {
492 /* Display off. */
493 if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
494 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
495 int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
496
497 if (!display_hint_sent) {
498 perform_hint_action(DISPLAY_STATE_HINT_ID,
499 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
500 display_hint_sent = 1;
501 }
502 } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
503 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
504 int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
505
506 if (!display_hint_sent) {
507 perform_hint_action(DISPLAY_STATE_HINT_ID,
508 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
509 display_hint_sent = 1;
510 }
511 } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
512 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
513 if (saved_interactive_mode == 1){
514 /* Display turned off. */
515 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
516 if (!slack_node_rw_failed) {
517 ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
518 }
519
520 rc = 1;
521 } else {
522 saved_dcvs_cpu0_slack_max = atoi(tmp_str);
523 }
524
525 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
526 if (!slack_node_rw_failed) {
527 ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
528 }
529
530 rc = 1;
531 } else {
532 saved_dcvs_cpu0_slack_min = atoi(tmp_str);
533 }
534
535 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
536 if (!slack_node_rw_failed) {
537 ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
538 }
539
540 rc = 1;
541 } else {
542 saved_mpdecision_slack_max = atoi(tmp_str);
543 }
544
545 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
546 if(!slack_node_rw_failed) {
547 ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
548 }
549
550 rc = 1;
551 } else {
552 saved_mpdecision_slack_min = atoi(tmp_str);
553 }
554
555 /* Write new values. */
556 if (saved_dcvs_cpu0_slack_max != -1) {
557 snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
558
559 if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
560 if (!slack_node_rw_failed) {
561 ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
562 }
563
564 rc = 1;
565 }
566 }
567
568 if (saved_dcvs_cpu0_slack_min != -1) {
569 snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
570
571 if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
572 if(!slack_node_rw_failed) {
573 ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
574 }
575
576 rc = 1;
577 }
578 }
579
580 if (saved_mpdecision_slack_max != -1) {
581 snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
582
583 if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
584 if(!slack_node_rw_failed) {
585 ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
586 }
587
588 rc = 1;
589 }
590 }
591
592 if (saved_mpdecision_slack_min != -1) {
593 snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
594
595 if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
596 if(!slack_node_rw_failed) {
597 ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
598 }
599
600 rc = 1;
601 }
602 }
603 }
604
605 slack_node_rw_failed = rc;
606 }
607 } else {
608 /* Display on. */
609 if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
610 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
611 undo_hint_action(DISPLAY_STATE_HINT_ID);
612 display_hint_sent = 0;
613 } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
614 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
615 undo_hint_action(DISPLAY_STATE_HINT_ID);
616 display_hint_sent = 0;
617 } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
618 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
619 if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
620 /* Display turned on. Restore if possible. */
621 if (saved_dcvs_cpu0_slack_max != -1) {
622 snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
623
624 if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
625 if (!slack_node_rw_failed) {
626 ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
627 }
628
629 rc = 1;
630 }
631 }
632
633 if (saved_dcvs_cpu0_slack_min != -1) {
634 snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
635
636 if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
637 if (!slack_node_rw_failed) {
638 ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
639 }
640
641 rc = 1;
642 }
643 }
644
645 if (saved_mpdecision_slack_max != -1) {
646 snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
647
648 if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
649 if (!slack_node_rw_failed) {
650 ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
651 }
652
653 rc = 1;
654 }
655 }
656
657 if (saved_mpdecision_slack_min != -1) {
658 snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
659
660 if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
661 if (!slack_node_rw_failed) {
662 ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
663 }
664
665 rc = 1;
666 }
667 }
668 }
669
670 slack_node_rw_failed = rc;
671 }
672 }
673
674 saved_interactive_mode = !!on;
675 }
676
get_number_of_platform_modes(struct power_module * module)677 static ssize_t get_number_of_platform_modes(struct power_module *module) {
678 return PLATFORM_SLEEP_MODES;
679 }
680
get_voter_list(struct power_module * module,size_t * voter)681 static int get_voter_list(struct power_module *module, size_t *voter) {
682 voter[0] = XO_VOTERS;
683 voter[1] = VMIN_VOTERS;
684
685 return 0;
686 }
687
extract_stats(uint64_t * list,char * file,unsigned int num_parameters,unsigned int index)688 static int extract_stats(uint64_t *list, char *file,
689 unsigned int num_parameters, unsigned int index) {
690 FILE *fp;
691 ssize_t read;
692 size_t len;
693 char *line;
694 int ret;
695
696 fp = fopen(file, "r");
697 if (fp == NULL) {
698 ret = -errno;
699 ALOGE("%s: failed to open: %s", __func__, strerror(errno));
700 return ret;
701 }
702
703 for (line = NULL, len = 0;
704 ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
705 free(line), line = NULL, len = 0) {
706 uint64_t value;
707 char* offset;
708
709 size_t begin = strspn(line, " \t");
710 if (strncmp(line + begin, parameter_names[index], strlen(parameter_names[index]))) {
711 continue;
712 }
713
714 offset = memchr(line, ':', len);
715 if (!offset) {
716 continue;
717 }
718
719 if (!strcmp(file, RPM_MASTER_STAT)) {
720 /* RPM_MASTER_STAT is reported in hex */
721 sscanf(offset, ":%" SCNx64, &value);
722 /* Duration is reported in rpm SLEEP TICKS */
723 if (!strcmp(parameter_names[index], "xo_accumulated_duration")) {
724 value /= RPM_CLK;
725 }
726 } else {
727 /* RPM_STAT is reported in decimal */
728 sscanf(offset, ":%" SCNu64, &value);
729 }
730 list[index] = value;
731 index++;
732 }
733 free(line);
734
735 fclose(fp);
736 return 0;
737 }
738
get_platform_low_power_stats(struct power_module * module,power_state_platform_sleep_state_t * list)739 static int get_platform_low_power_stats(struct power_module *module,
740 power_state_platform_sleep_state_t *list) {
741 uint64_t stats[sizeof(parameter_names)] = {0};
742 int ret;
743
744 if (!list) {
745 return -EINVAL;
746 }
747
748 ret = extract_stats(stats, RPM_STAT, RPM_PARAMETERS, 0);
749
750 if (ret) {
751 return ret;
752 }
753
754 ret = extract_stats(stats, RPM_MASTER_STAT, NUM_PARAMETERS, RPM_PARAMETERS);
755
756 if (ret) {
757 return ret;
758 }
759
760 /* Update statistics for XO_shutdown */
761 strcpy(list[0].name, "XO_shutdown");
762 list[0].total_transitions = stats[0];
763 list[0].residency_in_msec_since_boot = stats[1];
764 list[0].supported_only_in_suspend = false;
765 list[0].number_of_voters = XO_VOTERS;
766
767 /* Update statistics for APSS voter */
768 strcpy(list[0].voters[0].name, "APSS");
769 list[0].voters[0].total_time_in_msec_voted_for_since_boot = stats[4];
770 list[0].voters[0].total_number_of_times_voted_since_boot = stats[5];
771
772 /* Update statistics for MPSS voter */
773 strcpy(list[0].voters[1].name, "MPSS");
774 list[0].voters[1].total_time_in_msec_voted_for_since_boot = stats[6];
775 list[0].voters[1].total_number_of_times_voted_since_boot = stats[7];
776
777 /* Update statistics for ADSP voter */
778 strcpy(list[0].voters[2].name, "ADSP");
779 list[0].voters[2].total_time_in_msec_voted_for_since_boot = stats[8];
780 list[0].voters[2].total_number_of_times_voted_since_boot = stats[9];
781
782 /* Update statistics for SLPI voter */
783 strcpy(list[0].voters[3].name, "SLPI");
784 list[0].voters[3].total_time_in_msec_voted_for_since_boot = stats[10];
785 list[0].voters[3].total_number_of_times_voted_since_boot = stats[11];
786
787 /* Update statistics for VMIN state */
788 strcpy(list[1].name, "VMIN");
789 list[1].total_transitions = stats[2];
790 list[1].residency_in_msec_since_boot = stats[3];
791 list[1].supported_only_in_suspend = false;
792 list[1].number_of_voters = VMIN_VOTERS;
793
794 return 0;
795 }
796
power_open(const hw_module_t * module,const char * name,hw_device_t ** device)797 static int power_open(const hw_module_t* module, const char* name,
798 hw_device_t** device)
799 {
800 ALOGV("%s: enter; name=%s", __FUNCTION__, name);
801 int retval = 0; /* 0 is ok; -1 is error */
802
803 if (strcmp(name, POWER_HARDWARE_MODULE_ID) == 0) {
804 power_module_t *dev = (power_module_t *)calloc(1,
805 sizeof(power_module_t));
806
807 if (dev) {
808 /* Common hw_device_t fields */
809 dev->common.tag = HARDWARE_MODULE_TAG;
810 dev->common.module_api_version = POWER_MODULE_API_VERSION_0_5;
811 dev->common.module_api_version = HARDWARE_HAL_API_VERSION;
812
813 dev->init = power_init;
814 dev->powerHint = power_hint;
815 dev->setInteractive = set_interactive;
816 dev->get_number_of_platform_modes = get_number_of_platform_modes;
817 dev->get_platform_low_power_stats = get_platform_low_power_stats;
818 dev->get_voter_list = get_voter_list;
819
820 *device = (hw_device_t*)dev;
821 } else
822 retval = -ENOMEM;
823 } else {
824 retval = -EINVAL;
825 }
826
827 ALOGV("%s: exit %d", __FUNCTION__, retval);
828 return retval;
829 }
830
831 static struct hw_module_methods_t power_module_methods = {
832 .open = power_open,
833 };
834
835 struct power_module HAL_MODULE_INFO_SYM = {
836 .common = {
837 .tag = HARDWARE_MODULE_TAG,
838 .module_api_version = POWER_MODULE_API_VERSION_0_5,
839 .hal_api_version = HARDWARE_HAL_API_VERSION,
840 .id = POWER_HARDWARE_MODULE_ID,
841 .name = "QCOM Power HAL",
842 .author = "Qualcomm",
843 .methods = &power_module_methods,
844 },
845
846 .init = power_init,
847 .powerHint = power_hint,
848 .setInteractive = set_interactive,
849 .get_number_of_platform_modes = get_number_of_platform_modes,
850 .get_platform_low_power_stats = get_platform_low_power_stats,
851 .get_voter_list = get_voter_list
852 };
853