blob: 02440a6fedb342418bcbe8b879b8559cc79b1780 [file] [log] [blame]
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +01001/*
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
30#define LOG_NIDEBUG 0
31
32#include <errno.h>
33#include <string.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37#include <dlfcn.h>
38#include <stdlib.h>
39
40#define LOG_TAG "QTI PowerHAL"
41#include <utils/Log.h>
42#include <hardware/hardware.h>
43#include <hardware/power.h>
44
45#include "utils.h"
46#include "metadata-defs.h"
47#include "hint-data.h"
48#include "performance.h"
49#include "power-common.h"
50
51static int display_hint_sent;
52static int video_encode_hint_sent;
53static int current_power_profile = PROFILE_BALANCED;
54
55static void process_video_encode_hint(void *metadata);
56
57extern void interaction(int duration, int num_args, int opt_list[]);
58
59static int profile_high_performance[] = {
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010060 SCHED_BOOST_ON_V3, 0x1,
61 ALL_CPUS_PWR_CLPS_DIS_V3, 0x1,
62 CPUS_ONLINE_MIN_BIG, 0x2,
63 CPUS_ONLINE_MIN_LITTLE, 0x2,
64 MIN_FREQ_BIG_CORE_0, 0xFFF,
65 MIN_FREQ_LITTLE_CORE_0, 0xFFF,
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010066};
67
68static int profile_power_save[] = {
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010069 CPUS_ONLINE_MAX_LIMIT_BIG, 0x1,
70 MAX_FREQ_BIG_CORE_0, 0x3bf,
71 MAX_FREQ_LITTLE_CORE_0, 0x300,
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010072};
73
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010074static int profile_bias_power[] = {
75 MAX_FREQ_BIG_CORE_0, 0x4B0,
76 MAX_FREQ_LITTLE_CORE_0, 0x300,
77};
78
79static int profile_bias_performance[] = {
80 CPUS_ONLINE_MAX_LIMIT_BIG, 0x2,
81 CPUS_ONLINE_MAX_LIMIT_LITTLE, 0x2,
82 MIN_FREQ_BIG_CORE_0, 0x540,
83};
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010084
85int get_number_of_profiles() {
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010086 return 5;
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +010087}
88
89static void set_power_profile(int profile) {
90
91 if (profile == current_power_profile)
92 return;
93
94 ALOGV("%s: profile=%d", __func__, profile);
95
96 if (current_power_profile != PROFILE_BALANCED) {
97 undo_hint_action(DEFAULT_PROFILE_HINT_ID);
98 ALOGV("%s: hint undone", __func__);
99 }
100
101 if (profile == PROFILE_HIGH_PERFORMANCE) {
102 perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_high_performance,
103 ARRAY_SIZE(profile_high_performance));
104 ALOGD("%s: set performance mode", __func__);
105
106 } else if (profile == PROFILE_POWER_SAVE) {
107 perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_power_save,
108 ARRAY_SIZE(profile_power_save));
109 ALOGD("%s: set powersave", __func__);
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100110 } else if (profile == PROFILE_BIAS_POWER) {
111 perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_bias_power,
112 ARRAY_SIZE(profile_bias_power));
113 ALOGD("%s: Set bias power mode", __func__);
114
115 } else if (profile == PROFILE_BIAS_PERFORMANCE) {
116 perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_bias_performance,
117 ARRAY_SIZE(profile_bias_performance));
118 ALOGD("%s: Set bias perf mode", __func__);
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100119 }
120
121 current_power_profile = profile;
122}
123
124int power_hint_override(struct power_module *module, power_hint_t hint,
125 void *data)
126{
127 int duration, duration_hint;
128 static unsigned long long previous_boost_time = 0;
129 unsigned long long cur_boost_time;
130 struct timeval cur_boost_timeval = {0, 0};
131 double elapsed_time;
132 int resources_launch_boost[] = {
Ricardo Cerqueira94f4dc52016-07-16 02:31:00 +0100133 SCHED_BOOST_ON_V3, 0x1,
134 MAX_FREQ_BIG_CORE_0, 0xFFF,
135 MAX_FREQ_LITTLE_CORE_0, 0xFFF,
136 MIN_FREQ_BIG_CORE_0, 0xFFF,
137 MIN_FREQ_LITTLE_CORE_0, 0xFFF,
138 ALL_CPUS_PWR_CLPS_DIS_V3, 0x1,
139 STOR_CLK_SCALE_DIS, 0x1,
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100140 };
Ricardo Cerqueira94f4dc52016-07-16 02:31:00 +0100141
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100142 int resources_cpu_boost[] = {
Ricardo Cerqueira94f4dc52016-07-16 02:31:00 +0100143 SCHED_BOOST_ON_V3, 0x1,
144 MIN_FREQ_BIG_CORE_0, 0x3BF,
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100145 };
Ricardo Cerqueira94f4dc52016-07-16 02:31:00 +0100146
147 int resources_interaction_fling_boost[] = {
148 MIN_FREQ_BIG_CORE_0, 0x3BF,
149 MIN_FREQ_LITTLE_CORE_0, 0x300,
150 SCHED_BOOST_ON_V3, 0x1,
151 };
152
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100153 int resources_interaction_boost[] = {
Ricardo Cerqueira94f4dc52016-07-16 02:31:00 +0100154 MIN_FREQ_BIG_CORE_0, 0x300,
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100155 };
156
157 if (hint == POWER_HINT_SET_PROFILE) {
158 set_power_profile(*(int32_t *)data);
159 return HINT_HANDLED;
160 }
161
162 // Skip other hints in custom power modes
163 if (current_power_profile != PROFILE_BALANCED) {
164 return HINT_HANDLED;
165 }
166
167 switch (hint) {
168 case POWER_HINT_INTERACTION:
169 duration = 500;
170 duration_hint = 0;
171
172 if (data) {
173 duration_hint = *((int *)data);
174 }
175
176 duration = duration_hint > 0 ? duration_hint : 500;
177
178 gettimeofday(&cur_boost_timeval, NULL);
179 cur_boost_time = cur_boost_timeval.tv_sec * 1000000 + cur_boost_timeval.tv_usec;
180 elapsed_time = (double)(cur_boost_time - previous_boost_time);
181 if (elapsed_time > 750000)
182 elapsed_time = 750000;
183 // don't hint if it's been less than 250ms since last boost
184 // also detect if we're doing anything resembling a fling
185 // support additional boosting in case of flings
186 else if (elapsed_time < 250000 && duration <= 750)
187 return HINT_HANDLED;
188
189 previous_boost_time = cur_boost_time;
190
191 if (duration >= 1500) {
Ricardo Cerqueira94f4dc52016-07-16 02:31:00 +0100192 interaction(duration, ARRAY_SIZE(resources_interaction_fling_boost),
193 resources_interaction_fling_boost);
Ricardo Cerqueirac1deb0b2016-07-16 02:13:02 +0100194 } else {
195 interaction(duration, ARRAY_SIZE(resources_interaction_boost),
196 resources_interaction_boost);
197 }
198 return HINT_HANDLED;
199 case POWER_HINT_LAUNCH_BOOST:
200 duration = 2000;
201 interaction(duration, ARRAY_SIZE(resources_launch_boost),
202 resources_launch_boost);
203 return HINT_HANDLED;
204 case POWER_HINT_CPU_BOOST:
205 duration = *(int32_t *)data / 1000;
206 if (duration > 0) {
207 interaction(duration, ARRAY_SIZE(resources_cpu_boost),
208 resources_cpu_boost);
209 }
210 return HINT_HANDLED;
211 case POWER_HINT_VIDEO_ENCODE:
212 process_video_encode_hint(data);
213 return HINT_HANDLED;
214 }
215 return HINT_NONE;
216}
217
218int set_interactive_override(struct power_module *module, int on)
219{
220 char governor[80];
221
222 ALOGI("Got set_interactive hint");
223
224 if (get_scaling_governor_check_cores(governor, sizeof(governor),CPU0) == -1) {
225 if (get_scaling_governor_check_cores(governor, sizeof(governor),CPU1) == -1) {
226 if (get_scaling_governor_check_cores(governor, sizeof(governor),CPU2) == -1) {
227 if (get_scaling_governor_check_cores(governor, sizeof(governor),CPU3) == -1) {
228 ALOGE("Can't obtain scaling governor.");
229 return HINT_HANDLED;
230 }
231 }
232 }
233 }
234
235 if (!on) {
236 /* Display off. */
237 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
238 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
239 int resource_values[] = {TR_MS_CPU0_50, TR_MS_CPU4_50};
240
241 if (!display_hint_sent) {
242 perform_hint_action(DISPLAY_STATE_HINT_ID,
243 resource_values, ARRAY_SIZE(resource_values));
244 display_hint_sent = 1;
245 }
246 } /* Perf time rate set for CORE0,CORE4 8952 target*/
247
248 } else {
249 /* Display on. */
250 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
251 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
252
253 undo_hint_action(DISPLAY_STATE_HINT_ID);
254 display_hint_sent = 0;
255 }
256 }
257 return HINT_HANDLED;
258}
259
260/* Video Encode Hint */
261static void process_video_encode_hint(void *metadata)
262{
263 char governor[80];
264 struct video_encode_metadata_t video_encode_metadata;
265
266 ALOGI("Got process_video_encode_hint");
267
268 if (get_scaling_governor_check_cores(governor,
269 sizeof(governor),CPU0) == -1) {
270 if (get_scaling_governor_check_cores(governor,
271 sizeof(governor),CPU1) == -1) {
272 if (get_scaling_governor_check_cores(governor,
273 sizeof(governor),CPU2) == -1) {
274 if (get_scaling_governor_check_cores(governor,
275 sizeof(governor),CPU3) == -1) {
276 ALOGE("Can't obtain scaling governor.");
277 return;
278 }
279 }
280 }
281 }
282
283 /* Initialize encode metadata struct fields. */
284 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
285 video_encode_metadata.state = -1;
286 video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
287
288 if (metadata) {
289 if (parse_video_encode_metadata((char *)metadata,
290 &video_encode_metadata) == -1) {
291 ALOGE("Error occurred while parsing metadata.");
292 return;
293 }
294 } else {
295 return;
296 }
297
298 if (video_encode_metadata.state == 1) {
299 if ((strncmp(governor, INTERACTIVE_GOVERNOR,
300 strlen(INTERACTIVE_GOVERNOR)) == 0) &&
301 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
302 int resource_values[] = {TR_MS_CPU0_30, TR_MS_CPU4_30};
303 if (!video_encode_hint_sent) {
304 perform_hint_action(video_encode_metadata.hint_id,
305 resource_values,
306 ARRAY_SIZE(resource_values));
307 video_encode_hint_sent = 1;
308 }
309 }
310 } else if (video_encode_metadata.state == 0) {
311 if ((strncmp(governor, INTERACTIVE_GOVERNOR,
312 strlen(INTERACTIVE_GOVERNOR)) == 0) &&
313 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
314 undo_hint_action(video_encode_metadata.hint_id);
315 video_encode_hint_sent = 0;
316 return ;
317 }
318 }
319 return;
320}