summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'omap5/sgx_src/eurasia_km/services4/system/omap4/sgxfreq_on3demand.c')
-rw-r--r--omap5/sgx_src/eurasia_km/services4/system/omap4/sgxfreq_on3demand.c324
1 files changed, 0 insertions, 324 deletions
diff --git a/omap5/sgx_src/eurasia_km/services4/system/omap4/sgxfreq_on3demand.c b/omap5/sgx_src/eurasia_km/services4/system/omap4/sgxfreq_on3demand.c
deleted file mode 100644
index c4e4bd9..0000000
--- a/omap5/sgx_src/eurasia_km/services4/system/omap4/sgxfreq_on3demand.c
+++ /dev/null
@@ -1,324 +0,0 @@
1/*
2 * Copyright (C) 2012 Texas Instruments, Inc
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/sysfs.h>
18#include <linux/vmalloc.h>
19#include <asm/io.h>
20#include "sgxfreq.h"
21
22static int on3demand_start(struct sgxfreq_sgx_data *data);
23static void on3demand_stop(void);
24static void on3demand_predict(void);
25static void on3demand_frame_done(void);
26static void on3demand_active(void);
27static void on3demand_timeout(struct work_struct *work);
28
29
30static struct sgxfreq_governor on3demand_gov = {
31 .name = "on3demand",
32 .gov_start = on3demand_start,
33 .gov_stop = on3demand_stop,
34 .sgx_frame_done = on3demand_frame_done,
35 .sgx_active = on3demand_active,
36};
37
38static struct on3demand_data {
39 unsigned int load;
40 unsigned int up_threshold;
41 unsigned int down_threshold;
42 unsigned int history_size;
43 unsigned long prev_total_idle;
44 unsigned long prev_total_active;
45 unsigned int low_load_cnt;
46 unsigned int poll_interval;
47 unsigned long delta_active;
48 unsigned long delta_idle;
49 bool polling_enabled;
50 struct delayed_work work;
51 struct mutex mutex;
52} odd;
53
54#define ON3DEMAND_DEFAULT_UP_THRESHOLD 80
55#define ON3DEMAND_DEFAULT_DOWN_THRESHOLD 30
56#define ON3DEMAND_DEFAULT_HISTORY_SIZE_THRESHOLD 5
57/* For Live wallpaper frame done at interval of ~64ms */
58#define ON3DEMAND_DEFAULT_POLL_INTERVAL 75
59
60/*FIXME: This should be dynamic and queried from platform */
61#define ON3DEMAND_FRAME_DONE_DEADLINE_MS 16
62
63
64/*********************** begin sysfs interface ***********************/
65
66extern struct kobject *sgxfreq_kobj;
67
68static ssize_t show_down_threshold(struct device *dev,
69 struct device_attribute *attr, char *buf)
70{
71 return sprintf(buf, "%u\n", odd.down_threshold);
72}
73
74static ssize_t store_down_threshold(struct device *dev,
75 struct device_attribute *attr, const char *buf, size_t count)
76{
77 int ret;
78 unsigned int thres;
79
80 ret = sscanf(buf, "%u", &thres);
81 if (ret != 1)
82 return -EINVAL;
83
84 mutex_lock(&odd.mutex);
85
86 if (thres <= 100) {
87 odd.down_threshold = thres;
88 odd.low_load_cnt = 0;
89 } else {
90 return -EINVAL;
91 }
92
93 mutex_unlock(&odd.mutex);
94
95 return count;
96}
97
98static ssize_t show_up_threshold(struct device *dev,
99 struct device_attribute *attr, char *buf)
100{
101 return sprintf(buf, "%u\n", odd.up_threshold);
102}
103
104static ssize_t store_up_threshold(struct device *dev,
105 struct device_attribute *attr, const char *buf, size_t count)
106{
107 int ret;
108 unsigned int thres;
109
110 ret = sscanf(buf, "%u", &thres);
111 if (ret != 1)
112 return -EINVAL;
113
114 mutex_lock(&odd.mutex);
115
116 if (thres <= 100) {
117 odd.up_threshold = thres;
118 odd.low_load_cnt = 0;
119 } else {
120 return -EINVAL;
121 }
122
123 mutex_unlock(&odd.mutex);
124
125 return count;
126}
127
128static ssize_t show_history_size(struct device *dev,
129 struct device_attribute *attr, char *buf)
130{
131 return sprintf(buf, "%u\n", odd.history_size);
132}
133
134static ssize_t store_history_size(struct device *dev,
135 struct device_attribute *attr, const char *buf, size_t count)
136{
137 int ret;
138 unsigned int size;
139
140 ret = sscanf(buf, "%u", &size);
141 if (ret != 1)
142 return -EINVAL;
143
144 mutex_lock(&odd.mutex);
145
146 if (size >= 1) {
147 odd.history_size = size;
148 odd.low_load_cnt = 0;
149 } else {
150 return -EINVAL;
151 }
152
153 mutex_unlock(&odd.mutex);
154
155 return count;
156}
157
158static ssize_t show_load(struct device *dev,
159 struct device_attribute *attr, char *buf)
160{
161 return sprintf(buf, "%u\n", odd.load);
162}
163
164static DEVICE_ATTR(down_threshold, 0644,
165 show_down_threshold, store_down_threshold);
166static DEVICE_ATTR(up_threshold, 0644,
167 show_up_threshold, store_up_threshold);
168static DEVICE_ATTR(history_size, 0644,
169 show_history_size, store_history_size);
170static DEVICE_ATTR(load, 0444,
171 show_load, NULL);
172
173static struct attribute *on3demand_attributes[] = {
174 &dev_attr_down_threshold.attr,
175 &dev_attr_up_threshold.attr,
176 &dev_attr_history_size.attr,
177 &dev_attr_load.attr,
178 NULL
179};
180
181static struct attribute_group on3demand_attr_group = {
182 .attrs = on3demand_attributes,
183 .name = "on3demand",
184};
185/************************ end sysfs interface ************************/
186
187int on3demand_init(void)
188{
189 int ret;
190
191 mutex_init(&odd.mutex);
192
193 ret = sgxfreq_register_governor(&on3demand_gov);
194 if (ret)
195 return ret;
196
197 return 0;
198}
199
200int on3demand_deinit(void)
201{
202 return 0;
203}
204
205static int on3demand_start(struct sgxfreq_sgx_data *data)
206{
207 int ret;
208
209 odd.load = 0;
210 odd.up_threshold = ON3DEMAND_DEFAULT_UP_THRESHOLD;
211 odd.down_threshold = ON3DEMAND_DEFAULT_DOWN_THRESHOLD;
212 odd.history_size = ON3DEMAND_DEFAULT_HISTORY_SIZE_THRESHOLD;
213 odd.prev_total_active = 0;
214 odd.prev_total_idle = 0;
215 odd.low_load_cnt = 0;
216 odd.poll_interval = ON3DEMAND_DEFAULT_POLL_INTERVAL;
217 odd.polling_enabled = false;
218
219 INIT_DELAYED_WORK(&odd.work, on3demand_timeout);
220
221 ret = sysfs_create_group(sgxfreq_kobj, &on3demand_attr_group);
222 if (ret)
223 return ret;
224
225 return 0;
226}
227
228static void on3demand_stop(void)
229{
230 cancel_delayed_work_sync(&odd.work);
231 sysfs_remove_group(sgxfreq_kobj, &on3demand_attr_group);
232}
233
234static void on3demand_predict(void)
235{
236 static unsigned short first_sample = 1;
237 unsigned long total_active, total_idle;
238 unsigned long freq;
239
240 if (first_sample == 1) {
241 first_sample = 0;
242 odd.prev_total_active = sgxfreq_get_total_active_time();
243 odd.prev_total_idle = sgxfreq_get_total_idle_time();
244 return;
245 }
246
247 /* Sample new active and idle times */
248 total_active = sgxfreq_get_total_active_time();
249 total_idle = sgxfreq_get_total_idle_time();
250
251 /* Compute load */
252 odd.delta_active = __delta32(total_active, odd.prev_total_active);
253 odd.delta_idle = __delta32(total_idle, odd.prev_total_idle);
254
255 /*
256 * If SGX was active for longer than frame display time (1/fps),
257 * scale to highest possible frequency.
258 */
259 if (odd.delta_active > ON3DEMAND_FRAME_DONE_DEADLINE_MS) {
260 odd.low_load_cnt = 0;
261 sgxfreq_set_freq_request(sgxfreq_get_freq_max());
262 }
263
264 if ((odd.delta_active + odd.delta_idle))
265 odd.load = (100 * odd.delta_active / (odd.delta_active + odd.delta_idle));
266
267 odd.prev_total_active = total_active;
268 odd.prev_total_idle = total_idle;
269
270 /* Scale GPU frequency on purpose */
271 if (odd.load >= odd.up_threshold) {
272 odd.low_load_cnt = 0;
273 sgxfreq_set_freq_request(sgxfreq_get_freq_max());
274 } else if (odd.load <= odd.down_threshold) {
275 if (odd.low_load_cnt == odd.history_size) {
276 /* Convert load to frequency */
277 freq = (sgxfreq_get_freq() * odd.load) / 100;
278 sgxfreq_set_freq_request(freq);
279 odd.low_load_cnt = 0;
280 } else {
281 odd.low_load_cnt++;
282 }
283 } else {
284 odd.low_load_cnt = 0;
285 }
286}
287
288
289static void on3demand_active(void)
290{
291 if (!odd.polling_enabled) {
292 sgxfreq_set_freq_request(sgxfreq_get_freq_max());
293 odd.low_load_cnt = 0;
294 odd.polling_enabled = true;
295 schedule_delayed_work(&odd.work, odd.poll_interval * HZ/1000);
296 }
297
298}
299
300static void on3demand_frame_done(void)
301{
302 if (odd.polling_enabled) {
303 cancel_delayed_work_sync(&odd.work);
304 schedule_delayed_work(&odd.work, odd.poll_interval * HZ/1000);
305 }
306 on3demand_predict();
307}
308
309static void on3demand_timeout(struct work_struct *work)
310{
311 /*
312 * If sgx was idle all throughout timer disable polling and
313 * enable it on next sgx active event
314 */
315 if (!odd.delta_active) {
316 sgxfreq_set_freq_request(sgxfreq_get_freq_min());
317 odd.low_load_cnt = 0;
318 odd.polling_enabled = false;
319 } else {
320 on3demand_predict();
321 odd.polling_enabled = true;
322 schedule_delayed_work(&odd.work, odd.poll_interval * HZ/1000);
323 }
324}