]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android/vendor-ti-am57x.git/blob - sgx_km/eurasia_km/services4/system/omap/sgxfreq_on3demand.c
sgx_km: Build SGX KM from source
[android/vendor-ti-am57x.git] / sgx_km / eurasia_km / services4 / system / omap / sgxfreq_on3demand.c
1 /*
2  * Copyright (C) 2012 Texas Instruments, Inc
3  *
4 @License        Dual MIT/GPLv2
6 The contents of this file are subject to the MIT license as set out below.
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 Alternatively, the contents of this file may be used under the terms of
19 the GNU General Public License Version 2 ("GPL") in which case the provisions
20 of GPL are applicable instead of those above.
22 If you wish to allow use of your version of this file only under the terms of
23 GPL, and not to allow others to use your version of this file under the terms
24 of the MIT license, indicate your decision by deleting the provisions above
25 and replace them with the notice and other provisions required by GPL as set
26 out in the file called "GPL-COPYING" included in this distribution. If you do
27 not delete the provisions above, a recipient may use your version of this file
28 under the terms of either the MIT license or GPL.
30 This License is also included in this distribution in the file called
31 "MIT-COPYING".
33 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
34 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
35 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
37 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 */
42 #include <linux/sysfs.h>
43 #include <linux/vmalloc.h>
44 #include <asm/io.h>
45 #include "sgxfreq.h"
47 static int on3demand_start(struct sgxfreq_sgx_data *data);
48 static void on3demand_stop(void);
49 static void on3demand_predict(void);
52 static struct sgxfreq_governor on3demand_gov = {
53         .name = "on3demand",
54         .gov_start = on3demand_start,
55         .gov_stop = on3demand_stop,
56         .sgx_frame_done = on3demand_predict
57 };
59 static struct on3demand_data {
60         unsigned int load;
61         unsigned int up_threshold;
62         unsigned int down_threshold;
63         unsigned int history_size;
64         unsigned long prev_total_idle;
65         unsigned long prev_total_active;
66         unsigned int low_load_cnt;
67         struct mutex mutex;
68 } odd;
70 #define ON3DEMAND_DEFAULT_UP_THRESHOLD                  80
71 #define ON3DEMAND_DEFAULT_DOWN_THRESHOLD                30
72 #define ON3DEMAND_DEFAULT_HISTORY_SIZE_THRESHOLD        5
74 /*FIXME: This should be dynamic and queried from platform */
75 #define ON3DEMAND_FRAME_DONE_DEADLINE_MS 16
78 /*********************** begin sysfs interface ***********************/
80 extern struct kobject *sgxfreq_kobj;
82 static ssize_t show_down_threshold(struct device *dev,
83         struct device_attribute *attr, char *buf)
84 {
85         return sprintf(buf, "%u\n", odd.down_threshold);
86 }
88 static ssize_t store_down_threshold(struct device *dev,
89         struct device_attribute *attr, const char *buf, size_t count)
90 {
91         int ret;
92         unsigned int thres;
94         ret = sscanf(buf, "%u", &thres);
95         if (ret != 1)
96                 return -EINVAL;
98         mutex_lock(&odd.mutex);
100         if (thres <= 100) {
101                 odd.down_threshold = thres;
102                 odd.low_load_cnt = 0;
103         } else {
104                 return -EINVAL;
105         }
107         mutex_unlock(&odd.mutex);
109         return count;
112 static ssize_t show_up_threshold(struct device *dev,
113         struct device_attribute *attr, char *buf)
115         return sprintf(buf, "%u\n", odd.up_threshold);
118 static ssize_t store_up_threshold(struct device *dev,
119         struct device_attribute *attr, const char *buf, size_t count)
121         int ret;
122         unsigned int thres;
124         ret = sscanf(buf, "%u", &thres);
125         if (ret != 1)
126                 return -EINVAL;
128         mutex_lock(&odd.mutex);
130         if (thres <= 100) {
131                 odd.up_threshold = thres;
132                 odd.low_load_cnt = 0;
133         } else {
134                 return -EINVAL;
135         }
137         mutex_unlock(&odd.mutex);
139         return count;
142 static ssize_t show_history_size(struct device *dev,
143         struct device_attribute *attr, char *buf)
145         return sprintf(buf, "%u\n", odd.history_size);
148 static ssize_t store_history_size(struct device *dev,
149         struct device_attribute *attr, const char *buf, size_t count)
151         int ret;
152         unsigned int size;
154         ret = sscanf(buf, "%u", &size);
155         if (ret != 1)
156                 return -EINVAL;
158         mutex_lock(&odd.mutex);
160         if (size >= 1) {
161                 odd.history_size = size;
162                 odd.low_load_cnt = 0;
163         } else {
164                 return -EINVAL;
165         }
167         mutex_unlock(&odd.mutex);
169         return count;
172 static ssize_t show_load(struct device *dev,
173         struct device_attribute *attr, char *buf)
175         return sprintf(buf, "%u\n", odd.load);
178 static DEVICE_ATTR(down_threshold, 0644,
179         show_down_threshold, store_down_threshold);
180 static DEVICE_ATTR(up_threshold, 0644,
181         show_up_threshold, store_up_threshold);
182 static DEVICE_ATTR(history_size, 0644,
183         show_history_size, store_history_size);
184 static DEVICE_ATTR(load, 0444,
185         show_load, NULL);
187 static struct attribute *on3demand_attributes[] = {
188         &dev_attr_down_threshold.attr,
189         &dev_attr_up_threshold.attr,
190         &dev_attr_history_size.attr,
191         &dev_attr_load.attr,
192         NULL
193 };
195 static struct attribute_group on3demand_attr_group = {
196         .attrs = on3demand_attributes,
197         .name = "on3demand",
198 };
199 /************************ end sysfs interface ************************/
201 int on3demand_init(void)
203         int ret;
205         mutex_init(&odd.mutex);
207         ret = sgxfreq_register_governor(&on3demand_gov);
208         if (ret)
209                 return ret;
211         return 0;
214 int on3demand_deinit(void)
216         return 0;
219 static int on3demand_start(struct sgxfreq_sgx_data *data)
221         int ret;
223         odd.load = 0;
224         odd.up_threshold = ON3DEMAND_DEFAULT_UP_THRESHOLD;
225         odd.down_threshold = ON3DEMAND_DEFAULT_DOWN_THRESHOLD;
226         odd.history_size = ON3DEMAND_DEFAULT_HISTORY_SIZE_THRESHOLD;
227         odd.prev_total_active = 0;
228         odd.prev_total_idle = 0;
229         odd.low_load_cnt = 0;
231         ret = sysfs_create_group(sgxfreq_kobj, &on3demand_attr_group);
232         if (ret)
233                 return ret;
235         return 0;
238 static void on3demand_stop(void)
240         sysfs_remove_group(sgxfreq_kobj, &on3demand_attr_group);
243 static void on3demand_predict(void)
245         static unsigned short first_sample = 1;
246         unsigned long total_active, delta_active;
247         unsigned long total_idle, delta_idle;
248         unsigned long freq;
250         if (first_sample == 1) {
251                 first_sample = 0;
252                 odd.prev_total_active = sgxfreq_get_total_active_time();
253                 odd.prev_total_idle = sgxfreq_get_total_idle_time();
254                 return;
255         }
257         /* Sample new active and idle times */
258         total_active = sgxfreq_get_total_active_time();
259         total_idle = sgxfreq_get_total_idle_time();
261         /* Compute load */
262         delta_active = __delta32(total_active, odd.prev_total_active);
263         delta_idle = __delta32(total_idle, odd.prev_total_idle);
265         /*
266          * If SGX was active for longer than frame display time (1/fps),
267          * scale to highest possible frequency.
268          */
269         if (delta_active > ON3DEMAND_FRAME_DONE_DEADLINE_MS) {
270                 odd.low_load_cnt = 0;
271                 sgxfreq_set_freq_request(sgxfreq_get_freq_max());
272         }
274         if ((delta_active + delta_idle))
275                 odd.load = (100 * delta_active / (delta_active + delta_idle));
276         odd.prev_total_active = total_active;
277         odd.prev_total_idle = total_idle;
279         /* Scale GPU frequency on purpose */
280         if (odd.load >= odd.up_threshold) {
281                 odd.low_load_cnt = 0;
282                 sgxfreq_set_freq_request(sgxfreq_get_freq_max());
283         } else if (odd.load <= odd.down_threshold) {
284                 if (odd.low_load_cnt == odd.history_size) {
285                         /* Convert load to frequency */
286                         freq = (sgxfreq_get_freq() * odd.load) / 100;
287                         sgxfreq_set_freq_request(freq);
288                         odd.low_load_cnt = 0;
289                 } else {
290                         odd.low_load_cnt++;
291                 }
292         } else {
293                 odd.low_load_cnt = 0;
294         }