blob: 6ea0568def564464f3bc1331caa1ba37ae00fbdf [file] [log] [blame]
Michael Bestas7af0fea2019-10-06 02:05:22 +03001/*
2 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
Michael Bestas6e8e0912019-10-06 04:51:28 +03003 * Copyright (C) 2018-2019 The LineageOS Project
Michael Bestas7af0fea2019-10-06 02:05:22 +03004 *
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
31#define LOG_NIDEBUG 0
32
33#include <dlfcn.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40
41#define LOG_TAG "QCOM PowerHAL"
42#include <hardware/hardware.h>
43#include <hardware/power.h>
44#include <log/log.h>
45
46#include "hint-data.h"
47#include "metadata-defs.h"
48#include "performance.h"
49#include "power-common.h"
50#include "utils.h"
51
Michael Bestas6e8e0912019-10-06 04:51:28 +030052/**
53 * Returns true if the target is APQ8064.
54 */
55static bool is_target_8064(void) {
56 static int is_8064 = -1;
57 int soc_id;
58
59 if (is_8064 >= 0) return is_8064;
60
61 soc_id = get_soc_id();
62 is_8064 = soc_id == 153;
63
64 return is_8064;
65}
66
67static int current_power_profile = PROFILE_BALANCED;
68
69// clang-format off
70static int profile_high_performance_8960[] = {
71 CPUS_ONLINE_MIN_2,
72};
73
74static int profile_high_performance_8064[] = {
75 CPUS_ONLINE_MIN_4,
76};
77
78static int profile_power_save_8960[] = {
79 /* Don't do anything for now */
80};
81
82static int profile_power_save_8064[] = {
83 CPUS_ONLINE_MAX_LIMIT_2,
84};
85// clang-format on
86
87#ifdef INTERACTION_BOOST
88int get_number_of_profiles() {
89 return 3;
90}
91#endif
92
93static int set_power_profile(void* data) {
94 int profile = data ? *((int*)data) : 0;
95 int ret = -EINVAL;
96 const char* profile_name = NULL;
97
98 if (profile == current_power_profile) return 0;
99
100 ALOGV("%s: Profile=%d", __func__, profile);
101
102 if (current_power_profile != PROFILE_BALANCED) {
103 undo_hint_action(DEFAULT_PROFILE_HINT_ID);
104 ALOGV("%s: Hint undone", __func__);
105 current_power_profile = PROFILE_BALANCED;
106 }
107
108 if (profile == PROFILE_POWER_SAVE) {
109 if (is_target_8064()) {
110 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_power_save_8064,
111 ARRAY_SIZE(profile_power_save_8064));
112 } else {
113 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_power_save_8960,
114 ARRAY_SIZE(profile_power_save_8960));
115 }
116 profile_name = "powersave";
117 } else if (profile == PROFILE_HIGH_PERFORMANCE) {
118 if (is_target_8064()) {
119 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_high_performance_8064,
120 ARRAY_SIZE(profile_high_performance_8064));
121 } else {
122 ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_high_performance_8960,
123 ARRAY_SIZE(profile_high_performance_8960));
124 }
125 profile_name = "performance";
126 } else if (profile == PROFILE_BALANCED) {
127 ret = 0;
128 profile_name = "balanced";
129 }
130
131 if (ret == 0) {
132 current_power_profile = profile;
133 ALOGD("%s: Set %s mode", __func__, profile_name);
134 }
135 return ret;
136}
137
Michael Bestas7af0fea2019-10-06 02:05:22 +0300138static int process_video_encode_hint(void* metadata) {
139 char governor[80];
140 struct video_encode_metadata_t video_encode_metadata;
141
142 if (!metadata) return HINT_NONE;
143
144 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
145 ALOGE("Can't obtain scaling governor.");
146 return HINT_NONE;
147 }
148
149 /* Initialize encode metadata struct fields */
150 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
151 video_encode_metadata.state = -1;
152 video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
153
154 if (parse_video_encode_metadata((char*)metadata, &video_encode_metadata) == -1) {
155 ALOGE("Error occurred while parsing metadata.");
156 return HINT_NONE;
157 }
158
159 if (video_encode_metadata.state == 1) {
160 if (is_interactive_governor(governor)) {
161 int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026,
162 THREAD_MIGRATION_SYNC_OFF, INTERACTIVE_IO_BUSY_OFF};
163 perform_hint_action(video_encode_metadata.hint_id, resource_values,
164 ARRAY_SIZE(resource_values));
165 return HINT_HANDLED;
166 }
167 } else if (video_encode_metadata.state == 0) {
168 if (is_interactive_governor(governor)) {
169 undo_hint_action(video_encode_metadata.hint_id);
170 return HINT_HANDLED;
171 }
172 }
173 return HINT_NONE;
174}
175
176static int process_video_decode_hint(void* metadata) {
177 char governor[80];
178 struct video_decode_metadata_t video_decode_metadata;
179
180 if (!metadata) return HINT_NONE;
181
182 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
183 ALOGE("Can't obtain scaling governor.");
184 return HINT_NONE;
185 }
186
187 /* Initialize encode metadata struct fields */
188 memset(&video_decode_metadata, 0, sizeof(struct video_decode_metadata_t));
189 video_decode_metadata.state = -1;
190 video_decode_metadata.hint_id = DEFAULT_VIDEO_DECODE_HINT_ID;
191
192 if (parse_video_decode_metadata((char*)metadata, &video_decode_metadata) == -1) {
193 ALOGE("Error occurred while parsing metadata.");
194 return HINT_NONE;
195 }
196
197 if (video_decode_metadata.state == 1) {
198 if (is_interactive_governor(governor)) {
199 int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026,
200 THREAD_MIGRATION_SYNC_OFF};
201 perform_hint_action(video_decode_metadata.hint_id, resource_values,
202 ARRAY_SIZE(resource_values));
203 return HINT_HANDLED;
204 }
205 } else if (video_decode_metadata.state == 0) {
206 if (is_interactive_governor(governor)) {
207 undo_hint_action(video_decode_metadata.hint_id);
208 return HINT_HANDLED;
209 }
210 }
211 return HINT_NONE;
212}
213
214int power_hint_override(power_hint_t hint, void* data) {
215 int ret_val = HINT_NONE;
Michael Bestas6e8e0912019-10-06 04:51:28 +0300216
217 if (hint == POWER_HINT_SET_PROFILE) {
218 if (set_power_profile(data) < 0) ALOGE("Setting power profile failed. perfd not started?");
219 return HINT_HANDLED;
220 }
221
222 // Skip other hints in high/low power modes
223 if (current_power_profile == PROFILE_POWER_SAVE ||
224 current_power_profile == PROFILE_HIGH_PERFORMANCE) {
225 return HINT_HANDLED;
226 }
227
Michael Bestas7af0fea2019-10-06 02:05:22 +0300228 switch (hint) {
229 case POWER_HINT_VIDEO_ENCODE:
230 ret_val = process_video_encode_hint(data);
231 break;
232 case POWER_HINT_VIDEO_DECODE:
233 ret_val = process_video_decode_hint(data);
234 break;
235 default:
236 break;
237 }
238 return ret_val;
239}
Michael Bestas43b9e352019-10-06 01:34:17 +0300240
241int set_interactive_override(int on) {
242 char governor[80];
243
244 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
245 ALOGE("Can't obtain scaling governor.");
246 return HINT_NONE;
247 }
248
249 if (!on) {
250 /* Display off */
251 if (is_interactive_governor(governor)) {
252 int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
253 perform_hint_action(DISPLAY_STATE_HINT_ID, resource_values,
254 ARRAY_SIZE(resource_values));
255 }
256 } else {
257 /* Display on */
258 if (is_interactive_governor(governor)) {
259 undo_hint_action(DISPLAY_STATE_HINT_ID);
260 }
261 }
262 return HINT_HANDLED;
263}