1 /* 2 * Copyright (c) 2015, 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 #define LOG_NDEBUG 1 30 31 #include <errno.h> 32 #include <string.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <dlfcn.h> 37 #include <stdlib.h> 38 39 #define LOG_TAG "QCOM PowerHAL" 40 #include <utils/Log.h> 41 #include <hardware/hardware.h> 42 #include <hardware/power.h> 43 44 #include "utils.h" 45 #include "metadata-defs.h" 46 #include "hint-data.h" 47 #include "performance.h" 48 #include "power-common.h" 49 50 static int display_hint_sent; 51 int launch_handle = -1; 52 int launch_mode; 53 54 #ifdef EXTRA_POWERHAL_HINTS 55 static int process_cam_preview_hint(void *metadata) 56 { 57 char governor[80]; 58 struct cam_preview_metadata_t cam_preview_metadata; 59 60 if (get_scaling_governor(governor, sizeof(governor)) == -1) { 61 ALOGE("Can't obtain scaling governor."); 62 63 return HINT_NONE; 64 } 65 66 /* Initialize encode metadata struct fields */ 67 memset(&cam_preview_metadata, 0, sizeof(struct cam_preview_metadata_t)); 68 cam_preview_metadata.state = -1; 69 cam_preview_metadata.hint_id = CAM_PREVIEW_HINT_ID; 70 71 if (metadata) { 72 if (parse_cam_preview_metadata((char *)metadata, &cam_preview_metadata) == 73 -1) { 74 ALOGE("Error occurred while parsing metadata."); 75 return HINT_NONE; 76 } 77 } else { 78 return HINT_NONE; 79 } 80 81 if (cam_preview_metadata.state == 1) { 82 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && 83 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { 84 /* sched and cpufreq params 85 * above_hispeed_delay for LVT - 40ms 86 * go hispeed load for LVT - 95 87 * hispeed freq for LVT - 556 MHz 88 * target load for LVT - 90 89 * above hispeed delay for sLVT - 40ms 90 * go hispeed load for sLVT - 95 91 * hispeed freq for sLVT - 556 MHz 92 * target load for sLVT - 90 93 * bus DCVS set to V2 config: 94 * low power ceil mpbs - 2500 95 * low power io percent - 50 96 */ 97 int resource_values[] = {0x41400000, 0x4, 0x41410000, 0x5F, 0x41414000, 0x22C, 98 0x41420000, 0x5A, 0x41400100, 0x4, 0x41410100, 0x5F, 0x41414100, 0x22C, 99 0x41420100, 0x5A, 0x41810000, 0x9C4, 0x41814000, 0x32}; 100 101 perform_hint_action(cam_preview_metadata.hint_id, 102 resource_values, sizeof(resource_values)/sizeof(resource_values[0])); 103 ALOGI("Cam Preview hint start"); 104 return HINT_HANDLED; 105 } else if ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) && 106 (strlen(governor) == strlen(SCHED_GOVERNOR))) { 107 /* 108 * lower bus BW to save power 109 * 0x41810000: low power ceil mpbs = 2500 110 * 0x41814000: low power io percent = 50 111 */ 112 int resource_values[] = {0x41810000, 0x9C4, 0x41814000, 0x32}; 113 114 perform_hint_action( 115 cam_preview_metadata.hint_id, resource_values, 116 sizeof(resource_values) / sizeof(resource_values[0])); 117 ALOGI("Cam Preview hint start"); 118 return HINT_HANDLED; 119 } 120 } else if (cam_preview_metadata.state == 0) { 121 if (((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && 122 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) || 123 ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) && 124 (strlen(governor) == strlen(SCHED_GOVERNOR)))) { 125 undo_hint_action(cam_preview_metadata.hint_id); 126 ALOGI("Cam Preview hint stop"); 127 return HINT_HANDLED; 128 } 129 } 130 return HINT_NONE; 131 } 132 #endif 133 134 static int process_boost(int boost_handle, int duration) 135 { 136 char governor[80]; 137 int eas_launch_resources[] = {0x40804000, 0xFFF, 0x40804100, 0xFFF, 138 0x40800000, 0xFFF, 0x40800100, 0xFFF, 139 0x41800000, 140, 0x40400000, 0x1}; 140 int hmp_launch_resources[] = {0x40C00000, 0x1, 0x40804000, 0xFFF, 141 0x40804100, 0xFFF, 0x40800000, 0xFFF, 142 0x40800100, 0xFFF, 0x41800000, 140, 143 0x40400000, 0x1}; 144 int* launch_resources; 145 size_t launch_resources_size; 146 147 if (get_scaling_governor(governor, sizeof(governor)) == -1) { 148 ALOGE("Can't obtain scaling governor."); 149 return -1; 150 } 151 if (strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) { 152 launch_resources = eas_launch_resources; 153 launch_resources_size = sizeof(eas_launch_resources) / sizeof(eas_launch_resources[0]); 154 } else if (strncmp(governor, INTERACTIVE_GOVERNOR, 155 strlen(INTERACTIVE_GOVERNOR)) == 0) { /*HMP boost*/ 156 launch_resources = hmp_launch_resources; 157 launch_resources_size = sizeof(hmp_launch_resources) / sizeof(hmp_launch_resources[0]); 158 } else { 159 ALOGE("Unsupported governor."); 160 return -1; 161 } 162 boost_handle = interaction_with_handle( 163 boost_handle, duration, launch_resources_size, launch_resources); 164 return boost_handle; 165 } 166 167 static int process_video_encode_hint(void *metadata) 168 { 169 char governor[80]; 170 struct video_encode_metadata_t video_encode_metadata; 171 static int boost_handle = -1; 172 173 if (get_scaling_governor(governor, sizeof(governor)) == -1) { 174 ALOGE("Can't obtain scaling governor."); 175 176 return HINT_NONE; 177 } 178 179 /* Initialize encode metadata struct fields */ 180 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t)); 181 video_encode_metadata.state = -1; 182 video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID; 183 184 if (metadata) { 185 if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) == 186 -1) { 187 ALOGE("Error occurred while parsing metadata."); 188 return HINT_NONE; 189 } 190 } else { 191 return HINT_NONE; 192 } 193 194 if (video_encode_metadata.state == 1) { 195 int duration = 2000; // boosts 2s for starting encoding 196 boost_handle = process_boost(boost_handle, duration); 197 ALOGV("LAUNCH ENCODER-ON: %d MS", duration); 198 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && 199 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { 200 /* 1. cpufreq params 201 * -above_hispeed_delay for LVT - 40ms 202 * -go hispeed load for LVT - 95 203 * -hispeed freq for LVT - 556 MHz 204 * -target load for LVT - 90 205 * -above hispeed delay for sLVT - 40ms 206 * -go hispeed load for sLVT - 95 207 * -hispeed freq for sLVT - 806 MHz 208 * -target load for sLVT - 90 209 * 2. bus DCVS set to V2 config: 210 * -low power ceil mpbs - 2500 211 * -low power io percent - 50 212 * 3. hysteresis optimization 213 * -bus dcvs hysteresis tuning 214 * -sample_ms of 10 ms 215 * -disable ignore_hispeed_notif 216 * -sLVT hispeed freq to 806MHz 217 */ 218 int resource_values[] = { 219 0x41810000, 0x9C4, 0x41814000, 0x32, 0x4180C000, 0x0, 0x41820000, 0xA, 220 0x41438100, 0x1, 0x41438000, 0x1 }; 221 222 perform_hint_action(video_encode_metadata.hint_id, 223 resource_values, sizeof(resource_values)/sizeof(resource_values[0])); 224 ALOGV("Video Encode hint start"); 225 return HINT_HANDLED; 226 } else if ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) && 227 (strlen(governor) == strlen(SCHED_GOVERNOR))) { 228 229 /* 1. bus DCVS set to V2 config: 230 * 0x41810000: low power ceil mpbs - 2500 231 * 0x41814000: low power io percent - 50 232 * 2. hysteresis optimization 233 * 0x4180C000: bus dcvs hysteresis tuning 234 * 0x41820000: sample_ms of 10 ms 235 */ 236 int resource_values[] = {0x41810000, 0x9C4, 0x41814000, 0x32, 237 0x4180C000, 0x0, 0x41820000, 0xA}; 238 239 perform_hint_action(video_encode_metadata.hint_id, 240 resource_values, sizeof(resource_values)/sizeof(resource_values[0])); 241 ALOGV("Video Encode hint start"); 242 return HINT_HANDLED; 243 } 244 } else if (video_encode_metadata.state == 0) { 245 // boost handle is intentionally not released, release_request(boost_handle); 246 if (((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && 247 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) || 248 ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) && 249 (strlen(governor) == strlen(SCHED_GOVERNOR)))) { 250 undo_hint_action(video_encode_metadata.hint_id); 251 ALOGV("Video Encode hint stop"); 252 return HINT_HANDLED; 253 } 254 } 255 return HINT_NONE; 256 } 257 258 static int process_activity_launch_hint(void *data) 259 { 260 // boost will timeout in 5s 261 int duration = 5000; 262 if (sustained_performance_mode || vr_mode) { 263 return HINT_HANDLED; 264 } 265 266 ALOGV("LAUNCH HINT: %s", data ? "ON" : "OFF"); 267 if (data && launch_mode == 0) { 268 launch_handle = process_boost(launch_handle, duration); 269 if (launch_handle > 0) { 270 launch_mode = 1; 271 ALOGV("Activity launch hint handled"); 272 return HINT_HANDLED; 273 } else { 274 return HINT_NONE; 275 } 276 } else if (data == NULL && launch_mode == 1) { 277 release_request(launch_handle); 278 launch_mode = 0; 279 return HINT_HANDLED; 280 } 281 return HINT_NONE; 282 } 283 284 int power_hint_override(struct power_module *module, power_hint_t hint, void *data) 285 { 286 int ret_val = HINT_NONE; 287 switch(hint) { 288 #ifdef EXTRA_POWERHAL_HINTS 289 case POWER_HINT_CAM_PREVIEW: 290 ret_val = process_cam_preview_hint(data); 291 break; 292 #endif 293 case POWER_HINT_VIDEO_ENCODE: 294 ret_val = process_video_encode_hint(data); 295 break; 296 case POWER_HINT_LAUNCH: 297 ret_val = process_activity_launch_hint(data); 298 break; 299 default: 300 break; 301 } 302 return ret_val; 303 } 304 305 int set_interactive_override(struct power_module *module, int on) 306 { 307 return HINT_HANDLED; /* Don't excecute this code path, not in use */ 308 char governor[80]; 309 310 if (get_scaling_governor(governor, sizeof(governor)) == -1) { 311 ALOGE("Can't obtain scaling governor."); 312 313 return HINT_NONE; 314 } 315 316 if (!on) { 317 /* Display off */ 318 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && 319 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { 320 int resource_values[] = {}; /* dummy node */ 321 if (!display_hint_sent) { 322 perform_hint_action(DISPLAY_STATE_HINT_ID, 323 resource_values, sizeof(resource_values)/sizeof(resource_values[0])); 324 display_hint_sent = 1; 325 ALOGV("Display Off hint start"); 326 return HINT_HANDLED; 327 } 328 } 329 } else { 330 /* Display on */ 331 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && 332 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { 333 undo_hint_action(DISPLAY_STATE_HINT_ID); 334 display_hint_sent = 0; 335 ALOGV("Display Off hint stop"); 336 return HINT_HANDLED; 337 } 338 } 339 return HINT_NONE; 340 } 341