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 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 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 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 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 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 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 467 int __attribute__ ((weak)) set_interactive_override(struct power_module *module, int on) 468 { 469 return HINT_NONE; 470 } 471 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 677 static ssize_t get_number_of_platform_modes(struct power_module *module) { 678 return PLATFORM_SLEEP_MODES; 679 } 680 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 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 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 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