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_NIDEBUG 0
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 #include <pthread.h>
39 #include <stdbool.h>
40
41 #define LOG_TAG "QCOMPowerHAL"
42 #include <utils/Log.h>
43 #include <hardware/hardware.h>
44 #include <hardware/power.h>
45
46 #include "utils.h"
47 #include "metadata-defs.h"
48 #include "hint-data.h"
49 #include "performance.h"
50 #include "power-common.h"
51
52 pthread_mutex_t video_encode_lock = PTHREAD_MUTEX_INITIALIZER;
53 uintptr_t video_encode_hint_counter = 0;
54 bool video_encode_hint_should_enable = false;
55 bool video_encode_hint_is_enabled = false;
56
57 static int new_hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
58 static int cur_hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
59
60 static const time_t VIDEO_ENCODE_DELAY_SECONDS = 2;
61 static const time_t VIDEO_ENCODE_DELAY_NSECONDS = 0;
62
video_encode_hint_function(void * arg)63 static void* video_encode_hint_function(void* arg) {
64 struct timespec tv = {0};
65 tv.tv_sec = VIDEO_ENCODE_DELAY_SECONDS;
66 tv.tv_nsec = VIDEO_ENCODE_DELAY_NSECONDS;
67 int nanosleep_ret = 0;
68 uintptr_t expected_counter = (uintptr_t)arg;
69
70 // delay the hint for two seconds
71 // the hint hotplugs the large CPUs, so this prevents the large CPUs from
72 // going offline until the camera has had time to startup
73 TEMP_FAILURE_RETRY(nanosleep(&tv, &tv));
74 pthread_mutex_lock(&video_encode_lock);
75
76 // check to ensure we should still turn on hint from this particular thread
77 // if should_enable is true but counter is different, another thread owns hint
78 // if should_enable is false, we've already quit the camera
79 if (video_encode_hint_should_enable == true && video_encode_hint_counter == expected_counter) {
80 /* sched and cpufreq params
81 A53: 4 cores online at 1.2GHz max, 960 min
82 A57: 4 cores online at 384 max, 384 min
83 */
84 int resource_values[] = {0x150C, 0x1F03, 0x2303};
85 perform_hint_action(new_hint_id,
86 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
87 cur_hint_id = new_hint_id;
88 video_encode_hint_is_enabled = true;
89 video_encode_hint_should_enable = false;
90 }
91
92 pthread_mutex_unlock(&video_encode_lock);
93 return NULL;
94 }
95
96 static int display_hint_sent;
97
process_video_encode_hint(void * metadata)98 static int process_video_encode_hint(void *metadata)
99 {
100 char governor[80];
101 struct video_encode_metadata_t video_encode_metadata;
102
103 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
104 ALOGE("Can't obtain scaling governor.");
105
106 return HINT_NONE;
107 }
108
109 /* Initialize encode metadata struct fields */
110 memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
111 video_encode_metadata.state = -1;
112 video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
113
114 if (metadata) {
115 if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) ==
116 -1) {
117 ALOGE("Error occurred while parsing metadata.");
118 return HINT_NONE;
119 }
120 } else {
121 return HINT_NONE;
122 }
123
124 if (video_encode_metadata.state == 1) {
125 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
126 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
127 pthread_t video_encode_hint_thread;
128 pthread_mutex_lock(&video_encode_lock);
129 new_hint_id = video_encode_metadata.hint_id;
130 if (video_encode_hint_counter < 65535) {
131 video_encode_hint_counter++;
132 } else {
133 video_encode_hint_counter = 0;
134 }
135 // start new thread to launch hint
136 video_encode_hint_should_enable = true;
137 if (pthread_create(&video_encode_hint_thread, NULL, video_encode_hint_function, (void*)video_encode_hint_counter) != 0) {
138 ALOGE("Error constructing hint thread");
139 video_encode_hint_should_enable = false;
140 pthread_mutex_unlock(&video_encode_lock);
141 return HINT_NONE;
142 }
143 pthread_detach(video_encode_hint_thread);
144 pthread_mutex_unlock(&video_encode_lock);
145
146 return HINT_HANDLED;
147 }
148 } else if (video_encode_metadata.state == 0) {
149 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
150 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
151 pthread_mutex_lock(&video_encode_lock);
152 video_encode_hint_should_enable = false;
153 if (video_encode_hint_is_enabled == true) {
154 undo_hint_action(cur_hint_id);
155 video_encode_hint_is_enabled = false;
156 }
157 pthread_mutex_unlock(&video_encode_lock);
158 return HINT_HANDLED;
159 }
160 }
161 return HINT_NONE;
162 }
163
power_hint_override(struct power_module * module,power_hint_t hint,void * data)164 int power_hint_override(struct power_module *module, power_hint_t hint, void *data)
165 {
166 int ret_val = HINT_NONE;
167 switch(hint) {
168 case POWER_HINT_VIDEO_ENCODE:
169 ret_val = process_video_encode_hint(data);
170 break;
171 default:
172 break;
173 }
174 return ret_val;
175 }
176
set_interactive_override(struct power_module * module,int on)177 int set_interactive_override(struct power_module *module, int on)
178 {
179 char governor[80];
180
181 if (get_scaling_governor(governor, sizeof(governor)) == -1) {
182 ALOGE("Can't obtain scaling governor.");
183
184 return HINT_NONE;
185 }
186
187 if (!on) {
188 /* Display off */
189 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
190 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
191 // sched upmigrate = 99, sched downmigrate = 95
192 // keep the big cores around, but make them very hard to use
193 int resource_values[] = {0x4E63, 0x4F5F};
194 if (!display_hint_sent) {
195 perform_hint_action(DISPLAY_STATE_HINT_ID,
196 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
197 display_hint_sent = 1;
198 return HINT_HANDLED;
199 }
200 }
201 } else {
202 /* Display on */
203 if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
204 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
205 undo_hint_action(DISPLAY_STATE_HINT_ID);
206 display_hint_sent = 0;
207 return HINT_HANDLED;
208 }
209 }
210 return HINT_NONE;
211 }
212