blob: 15d158a6ae00fab55903b64a6b61340dc79be9b6 [file] [log] [blame]
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -07001/*
2 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Michael Bestas47636f62018-05-25 21:30:28 +03003 * Copyright (C) 2018 The LineageOS Project
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -07004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 * * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 * * Neither the name of The Linux Foundation nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
Michael Bestas47636f62018-05-25 21:30:28 +030030
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -070031#define LOG_NIDEBUG 0
32
33#include <errno.h>
BeYkeRYktbd52e812018-12-13 06:42:35 +090034#include <time.h>
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -070035#include <string.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <dlfcn.h>
40#include <stdlib.h>
Rashed Abdel-Tawab9c14c9f2017-12-26 23:11:03 +020041#include <pthread.h>
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -070042
Michael Bestas1add9ac2018-03-25 22:56:44 +030043#define LOG_TAG "QCOM PowerHAL"
Rashed Abdel-Tawab9c14c9f2017-12-26 23:11:03 +020044#include <log/log.h>
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -070045#include <hardware/hardware.h>
46#include <hardware/power.h>
47
48#include "utils.h"
49#include "metadata-defs.h"
50#include "hint-data.h"
51#include "performance.h"
52#include "power-common.h"
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -070053
Sathish Ambley2fc05d02017-07-06 22:28:16 -070054#define NUM_PERF_MODES 3
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -070055
tomascus8b038b12019-02-19 17:15:58 +110056const int kMaxLaunchDuration = 5000; /* ms */
BeYkeRYktbd52e812018-12-13 06:42:35 +090057const int kMaxInteractiveDuration = 5000; /* ms */
tomascus1c38bac2019-02-13 14:42:27 +110058const int kMinInteractiveDuration = 400; /* ms */
BeYkeRYktbd52e812018-12-13 06:42:35 +090059
dianlujitao2f0ce462017-10-14 12:08:10 +080060static int current_power_profile = PROFILE_BALANCED;
61
dianlujitao2f0ce462017-10-14 12:08:10 +080062static int profile_high_performance[] = {
63 SCHED_BOOST_ON_V3, 0x1,
64 MIN_FREQ_BIG_CORE_0, 0xFFF,
65 MIN_FREQ_LITTLE_CORE_0, 0xFFF,
66 ALL_CPUS_PWR_CLPS_DIS_V3, 0x1,
67};
68
69static int profile_power_save[] = {
70 MAX_FREQ_BIG_CORE_0, 0x3E8,
71 MAX_FREQ_LITTLE_CORE_0, 0x3E8,
72};
73
74static int profile_bias_power[] = {
75 MAX_FREQ_BIG_CORE_0, 0x514,
76 MAX_FREQ_LITTLE_CORE_0, 0x3E8,
77};
78
79static int profile_bias_performance[] = {
80 MIN_FREQ_BIG_CORE_0, 0x578,
81};
82
Michael Bestas47636f62018-05-25 21:30:28 +030083#ifdef INTERACTION_BOOST
84int get_number_of_profiles()
85{
86 return 5;
87}
88#endif
dianlujitao2f0ce462017-10-14 12:08:10 +080089
dianlujitao8780cb72019-02-23 20:24:57 +080090static int set_power_profile(void *data)
Michael Bestas47636f62018-05-25 21:30:28 +030091{
dianlujitao8780cb72019-02-23 20:24:57 +080092 int profile = data ? *((int*)data) : 0;
Corinna Vinschen8599e3c2018-08-26 22:11:49 +020093 int ret = -EINVAL;
94 const char *profile_name = NULL;
95
dianlujitao2f0ce462017-10-14 12:08:10 +080096 if (profile == current_power_profile)
Corinna Vinschen8599e3c2018-08-26 22:11:49 +020097 return 0;
dianlujitao2f0ce462017-10-14 12:08:10 +080098
99 ALOGV("%s: Profile=%d", __func__, profile);
100
101 if (current_power_profile != PROFILE_BALANCED) {
102 undo_hint_action(DEFAULT_PROFILE_HINT_ID);
103 ALOGV("%s: Hint undone", __func__);
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200104 current_power_profile = PROFILE_BALANCED;
dianlujitao2f0ce462017-10-14 12:08:10 +0800105 }
106
107 if (profile == PROFILE_POWER_SAVE) {
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200108 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_power_save,
Michael Bestas47636f62018-05-25 21:30:28 +0300109 ARRAY_SIZE(profile_power_save));
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200110 profile_name = "powersave";
dianlujitao2f0ce462017-10-14 12:08:10 +0800111
112 } else if (profile == PROFILE_HIGH_PERFORMANCE) {
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200113 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID,
114 profile_high_performance, ARRAY_SIZE(profile_high_performance));
115 profile_name = "performance";
dianlujitao2f0ce462017-10-14 12:08:10 +0800116
117 } else if (profile == PROFILE_BIAS_POWER) {
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200118 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_bias_power,
Michael Bestas47636f62018-05-25 21:30:28 +0300119 ARRAY_SIZE(profile_bias_power));
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200120 profile_name = "bias power";
dianlujitao2f0ce462017-10-14 12:08:10 +0800121
122 } else if (profile == PROFILE_BIAS_PERFORMANCE) {
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200123 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID,
124 profile_bias_performance, ARRAY_SIZE(profile_bias_performance));
125 profile_name = "bias perf";
126 } else if (profile == PROFILE_BALANCED) {
127 ret = 0;
128 profile_name = "balanced";
dianlujitao2f0ce462017-10-14 12:08:10 +0800129 }
130
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200131 if (ret == 0) {
132 current_power_profile = profile;
133 ALOGD("%s: Set %s mode", __func__, profile_name);
134 }
135 return ret;
dianlujitao2f0ce462017-10-14 12:08:10 +0800136}
137
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700138typedef enum {
139 NORMAL_MODE = 0,
140 SUSTAINED_MODE = 1,
141 VR_MODE = 2,
142 VR_SUSTAINED_MODE = (SUSTAINED_MODE|VR_MODE),
143 INVALID_MODE = 0xFF
Michael Bestas47636f62018-05-25 21:30:28 +0300144} perf_mode_type_t;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700145
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700146typedef struct perf_mode {
147 perf_mode_type_t type;
148 int perf_hint_id;
Michael Bestas47636f62018-05-25 21:30:28 +0300149} perf_mode_t;
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700150
Michael Bestas47636f62018-05-25 21:30:28 +0300151perf_mode_t perf_modes[NUM_PERF_MODES] = {
152 { SUSTAINED_MODE, SUSTAINED_PERF_HINT },
153 { VR_MODE, VR_MODE_HINT },
154 { VR_SUSTAINED_MODE, VR_MODE_SUSTAINED_PERF_HINT }
155};
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700156
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700157static int current_mode = NORMAL_MODE;
158
Michael Bestas47636f62018-05-25 21:30:28 +0300159static inline int get_perfd_hint_id(perf_mode_type_t type) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700160 int i;
Michael Bestas47636f62018-05-25 21:30:28 +0300161 for (i = 0; i < NUM_PERF_MODES; i++) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700162 if (perf_modes[i].type == type) {
163 ALOGD("Hint id is 0x%x for mode 0x%x", perf_modes[i].perf_hint_id, type);
164 return perf_modes[i].perf_hint_id;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700165 }
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700166 }
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700167 ALOGD("Couldn't find the hint for mode 0x%x", type);
168 return 0;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700169}
170
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700171static int switch_mode(perf_mode_type_t mode) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700172 int hint_id = 0;
173 static int perfd_mode_handle = -1;
174
175 // release existing mode if any
176 if (CHECK_HANDLE(perfd_mode_handle)) {
177 ALOGD("Releasing handle 0x%x", perfd_mode_handle);
178 release_request(perfd_mode_handle);
179 perfd_mode_handle = -1;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700180 }
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700181 // switch to a perf mode
182 hint_id = get_perfd_hint_id(mode);
Michael Bestas47636f62018-05-25 21:30:28 +0300183 if (hint_id != 0) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700184 perfd_mode_handle = perf_hint_enable(hint_id, 0);
185 if (!CHECK_HANDLE(perfd_mode_handle)) {
186 ALOGE("Failed perf_hint_interaction for mode: 0x%x", mode);
187 return -1;
188 }
189 ALOGD("Acquired handle 0x%x", perfd_mode_handle);
190 }
191 return 0;
192}
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700193
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700194static int process_perf_hint(void *data, perf_mode_type_t mode) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700195 // enable
dianlujitao8780cb72019-02-23 20:24:57 +0800196 if (data) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700197 ALOGI("Enable request for mode: 0x%x", mode);
198 // check if mode is current mode
Michael Bestas47636f62018-05-25 21:30:28 +0300199 if (current_mode & mode) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700200 ALOGD("Mode 0x%x already enabled", mode);
201 return HINT_HANDLED;
202 }
203 // enable requested mode
Michael Bestas47636f62018-05-25 21:30:28 +0300204 if (0 != switch_mode(current_mode | mode)) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700205 ALOGE("Couldn't enable mode 0x%x", mode);
206 return HINT_NONE;
207 }
208 current_mode |= mode;
209 ALOGI("Current mode is 0x%x", current_mode);
210 // disable
211 } else {
212 ALOGI("Disable request for mode: 0x%x", mode);
213 // check if mode is enabled
Michael Bestas47636f62018-05-25 21:30:28 +0300214 if (!(current_mode & mode)) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700215 ALOGD("Mode 0x%x already disabled", mode);
216 return HINT_HANDLED;
217 }
Michael Bestas47636f62018-05-25 21:30:28 +0300218 // disable requested mode
219 if (0 != switch_mode(current_mode & ~mode)) {
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700220 ALOGE("Couldn't disable mode 0x%x", mode);
221 return HINT_NONE;
222 }
223 current_mode &= ~mode;
224 ALOGI("Current mode is 0x%x", current_mode);
225 }
226
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700227 return HINT_HANDLED;
228}
229
230static int process_video_encode_hint(void *metadata)
231{
232 char governor[80];
233 struct video_encode_metadata_t video_encode_metadata;
Ananth Raghavan Subramanian0c226b72017-06-27 21:28:43 -0700234 static int video_encode_handle = 0;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700235
Michael Bestas47636f62018-05-25 21:30:28 +0300236 if (!metadata) {
237 return HINT_NONE;
238 }
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700239
240 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
241 ALOGE("Can't obtain scaling governor.");
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700242 return HINT_NONE;
243 }
244
245 /* Initialize encode metadata struct fields */
246 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
247 video_encode_metadata.state = -1;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700248
Michael Bestas47636f62018-05-25 21:30:28 +0300249 if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) == -1) {
250 ALOGE("Error occurred while parsing metadata.");
251 return HINT_NONE;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700252 }
253
254 if (video_encode_metadata.state == 1) {
Michael Bestas47636f62018-05-25 21:30:28 +0300255 if (is_interactive_governor(governor)) {
256 video_encode_handle = perf_hint_enable(
257 VIDEO_ENCODE_HINT, 0);
258 return HINT_HANDLED;
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700259 }
260 } else if (video_encode_metadata.state == 0) {
Michael Bestas47636f62018-05-25 21:30:28 +0300261 if (is_interactive_governor(governor)) {
Ananth Raghavan Subramanian0c226b72017-06-27 21:28:43 -0700262 release_request(video_encode_handle);
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700263 return HINT_HANDLED;
264 }
265 }
266 return HINT_NONE;
267}
268
tomascus8b038b12019-02-19 17:15:58 +1100269static int process_activity_launch_hint(void *data)
BeYkeRYktbd52e812018-12-13 06:42:35 +0900270{
tomascus8b038b12019-02-19 17:15:58 +1100271 static int launch_handle = -1;
272 static int launch_mode = 0;
273
274 // release lock early if launch has finished
275 if (!data) {
276 if (CHECK_HANDLE(launch_handle)) {
277 release_request(launch_handle);
278 launch_handle = -1;
279 }
280 launch_mode = 0;
281 return HINT_HANDLED;
282 }
283
BeYkeRYktbd52e812018-12-13 06:42:35 +0900284 if (current_mode != NORMAL_MODE) {
285 ALOGV("%s: ignoring due to other active perf hints", __func__);
tomascus8b038b12019-02-19 17:15:58 +1100286 } else if (!launch_mode) {
287 launch_handle = perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST,
288 kMaxLaunchDuration, LAUNCH_BOOST_V1);
289 if (!CHECK_HANDLE(launch_handle)) {
290 ALOGE("Failed to perform launch boost");
291 return HINT_NONE;
292 }
293 launch_mode = 1;
BeYkeRYktbd52e812018-12-13 06:42:35 +0900294 }
295 return HINT_HANDLED;
296}
297
298static int process_interaction_hint(void *data)
299{
300 static struct timespec s_previous_boost_timespec;
301 static int s_previous_duration = 0;
302
303 struct timespec cur_boost_timespec;
304 long long elapsed_time;
305 int duration = kMinInteractiveDuration;
306
307 if (current_mode != NORMAL_MODE) {
308 ALOGV("%s: ignoring due to other active perf hints", __func__);
309 return HINT_HANDLED;
310 }
311
312 if (data) {
313 int input_duration = *((int*)data);
314 if (input_duration > duration) {
315 duration = (input_duration > kMaxInteractiveDuration) ?
316 kMaxInteractiveDuration : input_duration;
317 }
318 }
319
320 clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
321
322 elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
323 // don't hint if previous hint's duration covers this hint's duration
324 if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
325 return HINT_HANDLED;
326 }
327 s_previous_boost_timespec = cur_boost_timespec;
328 s_previous_duration = duration;
329
tomascus1c38bac2019-02-13 14:42:27 +1100330 perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
BeYkeRYktbd52e812018-12-13 06:42:35 +0900331
332 return HINT_HANDLED;
333}
334
Rashed Abdel-Tawab00b21852017-11-03 12:44:16 -0700335int power_hint_override(power_hint_t hint, void *data)
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700336{
337 int ret_val = HINT_NONE;
dianlujitao2f0ce462017-10-14 12:08:10 +0800338
339 if (hint == POWER_HINT_SET_PROFILE) {
dianlujitao8780cb72019-02-23 20:24:57 +0800340 if (set_power_profile(data) < 0)
Corinna Vinschen8599e3c2018-08-26 22:11:49 +0200341 ALOGE("Setting power profile failed. perf HAL not started?");
dianlujitao2f0ce462017-10-14 12:08:10 +0800342 return HINT_HANDLED;
343 }
344
Michael Bestas8ff509e2018-03-26 05:21:23 +0300345 // Skip other hints in high/low power modes
346 if (current_power_profile == PROFILE_POWER_SAVE ||
347 current_power_profile == PROFILE_HIGH_PERFORMANCE) {
dianlujitao2f0ce462017-10-14 12:08:10 +0800348 return HINT_HANDLED;
Michael Bestas8ff509e2018-03-26 05:21:23 +0300349 }
dianlujitao2f0ce462017-10-14 12:08:10 +0800350
Michael Bestas8ff509e2018-03-26 05:21:23 +0300351 switch (hint) {
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700352 case POWER_HINT_VIDEO_ENCODE:
353 ret_val = process_video_encode_hint(data);
354 break;
355 case POWER_HINT_SUSTAINED_PERFORMANCE:
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700356 ret_val = process_perf_hint(data, SUSTAINED_MODE);
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700357 break;
358 case POWER_HINT_VR_MODE:
Sathish Ambley2fc05d02017-07-06 22:28:16 -0700359 ret_val = process_perf_hint(data, VR_MODE);
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700360 break;
361 case POWER_HINT_INTERACTION:
BeYkeRYktbd52e812018-12-13 06:42:35 +0900362 ret_val = process_interaction_hint(data);
363 break;
364 case POWER_HINT_LAUNCH:
365 ret_val = process_activity_launch_hint(data);
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700366 break;
367 default:
368 break;
369 }
370 return ret_val;
371}
372
Rashed Abdel-Tawab00b21852017-11-03 12:44:16 -0700373int set_interactive_override(int UNUSED(on))
Ananth Raghavan Subramaniane432dbf2017-03-24 16:30:12 -0700374{
375 return HINT_HANDLED; /* Don't excecute this code path, not in use */
376}