blob: c7ddd047249b50af4a95ec53cb9ac10d2f15440d [file] [log] [blame]
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -07001/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
Michael Bestas47636f62018-05-25 21:30:28 +03003 * Copyright (C) 2018 The LineageOS Project
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -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 */
30
Michael Bestas47636f62018-05-25 21:30:28 +030031#define LOG_NIDEBUG 0
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -070032
33#include <errno.h>
BeYkeRYktbd52e812018-12-13 06:42:35 +090034#include <time.h>
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -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>
41
Michael Bestas1add9ac2018-03-25 22:56:44 +030042#define LOG_TAG "QCOM PowerHAL"
Ethan Chena42f4a82018-03-01 21:31:15 -080043#include <log/log.h>
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -070044#include <hardware/hardware.h>
45#include <hardware/power.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
Ananth Raghavan Subramanianb06e15f2017-09-14 22:34:10 -070053#define NUM_PERF_MODES 3
54
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -070055#define SYS_DISPLAY_PWR "/sys/kernel/hbtp/display_pwr"
56
tomascus8b038b12019-02-19 17:15:58 +110057const int kMaxLaunchDuration = 5000; /* ms */
BeYkeRYktbd52e812018-12-13 06:42:35 +090058const int kMaxInteractiveDuration = 5000; /* ms */
59const int kMinInteractiveDuration = 100; /* ms */
BeYkeRYktbd52e812018-12-13 06:42:35 +090060
Michael Bestas47636f62018-05-25 21:30:28 +030061static int display_fd;
62
Ananth Raghavan Subramanianb06e15f2017-09-14 22:34:10 -070063typedef enum {
64 NORMAL_MODE = 0,
65 SUSTAINED_MODE = 1,
66 VR_MODE = 2,
67 VR_SUSTAINED_MODE = (SUSTAINED_MODE|VR_MODE),
68 INVALID_MODE = 0xFF
69} perf_mode_type_t;
70
71typedef struct perf_mode {
72 perf_mode_type_t type;
73 int perf_hint_id;
74} perf_mode_t;
75
76perf_mode_t perf_modes[NUM_PERF_MODES] = {
77 { SUSTAINED_MODE, SUSTAINED_PERF_HINT },
78 { VR_MODE, VR_MODE_HINT },
79 { VR_SUSTAINED_MODE, VR_MODE_SUSTAINED_PERF_HINT }
80};
81
82static int current_mode = NORMAL_MODE;
83
84static inline int get_perfd_hint_id(perf_mode_type_t type) {
85 int i;
86 for (i = 0; i < NUM_PERF_MODES; i++) {
87 if (perf_modes[i].type == type) {
88 ALOGD("Hint id is 0x%x for mode 0x%x", perf_modes[i].perf_hint_id, type);
89 return perf_modes[i].perf_hint_id;
90 }
91 }
92 ALOGD("Couldn't find the hint for mode 0x%x", type);
93 return 0;
94}
95
96static int switch_mode(perf_mode_type_t mode) {
97 int hint_id = 0;
98 static int perfd_mode_handle = -1;
99
100 // release existing mode if any
101 if (CHECK_HANDLE(perfd_mode_handle)) {
102 ALOGD("Releasing handle 0x%x", perfd_mode_handle);
103 release_request(perfd_mode_handle);
104 perfd_mode_handle = -1;
105 }
106 // switch to a perf mode
107 hint_id = get_perfd_hint_id(mode);
108 if (hint_id != 0) {
109 perfd_mode_handle = perf_hint_enable(hint_id, 0);
110 if (!CHECK_HANDLE(perfd_mode_handle)) {
111 ALOGE("Failed perf_hint_interaction for mode: 0x%x", mode);
112 return -1;
113 }
114 ALOGD("Acquired handle 0x%x", perfd_mode_handle);
115 }
116 return 0;
117}
118
119static int process_perf_hint(void *data, perf_mode_type_t mode) {
120 // enable
dianlujitao8780cb72019-02-23 20:24:57 +0800121 if (data) {
Ananth Raghavan Subramanianb06e15f2017-09-14 22:34:10 -0700122 ALOGI("Enable request for mode: 0x%x", mode);
123 // check if mode is current mode
124 if (current_mode & mode) {
125 ALOGD("Mode 0x%x already enabled", mode);
126 return HINT_HANDLED;
127 }
128 // enable requested mode
129 if (0 != switch_mode(current_mode | mode)) {
130 ALOGE("Couldn't enable mode 0x%x", mode);
131 return HINT_NONE;
132 }
133 current_mode |= mode;
134 ALOGI("Current mode is 0x%x", current_mode);
135 // disable
136 } else {
137 ALOGI("Disable request for mode: 0x%x", mode);
138 // check if mode is enabled
139 if (!(current_mode & mode)) {
140 ALOGD("Mode 0x%x already disabled", mode);
141 return HINT_HANDLED;
142 }
143 // disable requested mode
144 if (0 != switch_mode(current_mode & ~mode)) {
145 ALOGE("Couldn't disable mode 0x%x", mode);
146 return HINT_NONE;
147 }
148 current_mode &= ~mode;
149 ALOGI("Current mode is 0x%x", current_mode);
150 }
151
152 return HINT_HANDLED;
153}
154
155static int process_video_encode_hint(void *metadata)
156{
157 char governor[80];
158 struct video_encode_metadata_t video_encode_metadata;
159 static int video_encode_handle = 0;
160
161 if (!metadata) {
162 return HINT_NONE;
163 }
164
165 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
166 ALOGE("Can't obtain scaling governor.");
167 return HINT_NONE;
168 }
169
170 /* Initialize encode metadata struct fields */
171 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
172 video_encode_metadata.state = -1;
173
174 if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) == -1) {
175 ALOGE("Error occurred while parsing metadata.");
176 return HINT_NONE;
177 }
178
179 if (video_encode_metadata.state == 1) {
180 if (is_interactive_governor(governor)) {
181 video_encode_handle = perf_hint_enable(
182 VIDEO_ENCODE_HINT, 0);
183 return HINT_HANDLED;
184 }
185 } else if (video_encode_metadata.state == 0) {
186 if (is_interactive_governor(governor)) {
187 release_request(video_encode_handle);
188 return HINT_HANDLED;
189 }
190 }
191 return HINT_NONE;
192}
193
tomascus8b038b12019-02-19 17:15:58 +1100194static int process_activity_launch_hint(void *data)
BeYkeRYktbd52e812018-12-13 06:42:35 +0900195{
tomascus8b038b12019-02-19 17:15:58 +1100196 static int launch_handle = -1;
197 static int launch_mode = 0;
198
199 // release lock early if launch has finished
200 if (!data) {
201 if (CHECK_HANDLE(launch_handle)) {
202 release_request(launch_handle);
203 launch_handle = -1;
204 }
205 launch_mode = 0;
206 return HINT_HANDLED;
207 }
208
BeYkeRYktbd52e812018-12-13 06:42:35 +0900209 if (current_mode != NORMAL_MODE) {
210 ALOGV("%s: ignoring due to other active perf hints", __func__);
tomascus8b038b12019-02-19 17:15:58 +1100211 } else if (!launch_mode) {
212 launch_handle = perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST,
213 kMaxLaunchDuration, LAUNCH_BOOST_V1);
214 if (!CHECK_HANDLE(launch_handle)) {
215 ALOGE("Failed to perform launch boost");
216 return HINT_NONE;
217 }
218 launch_mode = 1;
BeYkeRYktbd52e812018-12-13 06:42:35 +0900219 }
220 return HINT_HANDLED;
221}
222
223static int process_interaction_hint(void *data)
224{
225 static struct timespec s_previous_boost_timespec;
226 static int s_previous_duration = 0;
227
228 struct timespec cur_boost_timespec;
229 long long elapsed_time;
230 int duration = kMinInteractiveDuration;
231
232 if (current_mode != NORMAL_MODE) {
233 ALOGV("%s: ignoring due to other active perf hints", __func__);
234 return HINT_HANDLED;
235 }
236
237 if (data) {
238 int input_duration = *((int*)data);
239 if (input_duration > duration) {
240 duration = (input_duration > kMaxInteractiveDuration) ?
241 kMaxInteractiveDuration : input_duration;
242 }
243 }
244
245 clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
246
247 elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
248 // don't hint if previous hint's duration covers this hint's duration
249 if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
250 return HINT_HANDLED;
251 }
252 s_previous_boost_timespec = cur_boost_timespec;
253 s_previous_duration = duration;
254
tomascus1c38bac2019-02-13 14:42:27 +1100255 perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
256
BeYkeRYktbd52e812018-12-13 06:42:35 +0900257 return HINT_HANDLED;
258}
259
Bruno Martins2d1ce222018-07-05 16:38:40 +0100260int power_hint_override(power_hint_t hint, void *data)
Bhargav Upperlae31cdff2017-08-15 12:22:49 -0700261{
262 int ret_val = HINT_NONE;
Michael Bestas47636f62018-05-25 21:30:28 +0300263 switch (hint) {
Ananth Raghavan Subramanianb06e15f2017-09-14 22:34:10 -0700264 case POWER_HINT_VIDEO_ENCODE:
265 ret_val = process_video_encode_hint(data);
266 break;
267 case POWER_HINT_SUSTAINED_PERFORMANCE:
268 ret_val = process_perf_hint(data, SUSTAINED_MODE);
269 break;
270 case POWER_HINT_VR_MODE:
271 ret_val = process_perf_hint(data, VR_MODE);
272 break;
Bhargav Upperlae31cdff2017-08-15 12:22:49 -0700273 case POWER_HINT_INTERACTION:
BeYkeRYktbd52e812018-12-13 06:42:35 +0900274 ret_val = process_interaction_hint(data);
275 break;
276 case POWER_HINT_LAUNCH:
277 ret_val = process_activity_launch_hint(data);
Michael Bestas47636f62018-05-25 21:30:28 +0300278 break;
Bhargav Upperlae31cdff2017-08-15 12:22:49 -0700279 default:
280 break;
281 }
282 return ret_val;
283}
284
Rashed Abdel-Tawaba2a70712017-12-31 01:21:40 +0200285int set_interactive_override(int on)
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700286{
287 static const char *display_on = "1";
288 static const char *display_off = "0";
289 char err_buf[80];
290 static int init_interactive_hint = 0;
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700291 int rc = 0;
292
Michael Bestas47636f62018-05-25 21:30:28 +0300293 if (init_interactive_hint == 0) {
294 // First time the display is turned off
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700295 display_fd = TEMP_FAILURE_RETRY(open(SYS_DISPLAY_PWR, O_RDWR));
296 if (display_fd < 0) {
Michael Bestas47636f62018-05-25 21:30:28 +0300297 strerror_r(errno, err_buf, sizeof(err_buf));
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700298 ALOGE("Error opening %s: %s\n", SYS_DISPLAY_PWR, err_buf);
Michael Bestas47636f62018-05-25 21:30:28 +0300299 } else {
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700300 init_interactive_hint = 1;
Michael Bestas47636f62018-05-25 21:30:28 +0300301 }
302 } else {
303 if (!on) {
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700304 /* Display off. */
305 rc = TEMP_FAILURE_RETRY(write(display_fd, display_off, strlen(display_off)));
306 if (rc < 0) {
Michael Bestas47636f62018-05-25 21:30:28 +0300307 strerror_r(errno, err_buf, sizeof(err_buf));
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700308 ALOGE("Error writing %s to %s: %s\n", display_off, SYS_DISPLAY_PWR, err_buf);
309 }
Michael Bestas47636f62018-05-25 21:30:28 +0300310 } else {
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700311 /* Display on */
312 rc = TEMP_FAILURE_RETRY(write(display_fd, display_on, strlen(display_on)));
313 if (rc < 0) {
Michael Bestas47636f62018-05-25 21:30:28 +0300314 strerror_r(errno, err_buf, sizeof(err_buf));
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700315 ALOGE("Error writing %s to %s: %s\n", display_on, SYS_DISPLAY_PWR, err_buf);
316 }
317 }
Michael Bestas47636f62018-05-25 21:30:28 +0300318 }
319 return HINT_HANDLED;
Ananth Raghavan Subramanianf976fa02017-05-18 20:46:03 -0700320}