aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/services4/system/omap/sgxfreq.c')
-rw-r--r--drivers/gpu/pvr/services4/system/omap/sgxfreq.c846
1 files changed, 846 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/services4/system/omap/sgxfreq.c b/drivers/gpu/pvr/services4/system/omap/sgxfreq.c
new file mode 100644
index 000000000000..6e5571eb5c98
--- /dev/null
+++ b/drivers/gpu/pvr/services4/system/omap/sgxfreq.c
@@ -0,0 +1,846 @@
1/*
2 * Copyright (C) 2012 Texas Instruments, Inc
3 *
4@License Dual MIT/GPLv2
5
6The contents of this file are subject to the MIT license as set out below.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18Alternatively, the contents of this file may be used under the terms of
19the GNU General Public License Version 2 ("GPL") in which case the provisions
20of GPL are applicable instead of those above.
21
22If you wish to allow use of your version of this file only under the terms of
23GPL, and not to allow others to use your version of this file under the terms
24of the MIT license, indicate your decision by deleting the provisions above
25and replace them with the notice and other provisions required by GPL as set
26out in the file called "GPL-COPYING" included in this distribution. If you do
27not delete the provisions above, a recipient may use your version of this file
28under the terms of either the MIT license or GPL.
29
30This License is also included in this distribution in the file called
31"MIT-COPYING".
32
33EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
34PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
35BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
37COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40*/
41
42#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
43#include <linux/pm_opp.h>
44#include <linux/of.h>
45#else
46#include <linux/opp.h>
47#endif
48#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
49#include <plat/gpu.h>
50#endif
51
52#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
53#include <linux/pm_voltage_domain.h>
54#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0))
55#include <linux/regulator/consumer.h>
56#endif
57
58#include "sgxfreq.h"
59
60static struct sgxfreq_data {
61 int freq_cnt;
62 unsigned long *freq_list;
63 unsigned long freq;
64 unsigned long freq_request;
65 unsigned long freq_limit;
66 unsigned long total_idle_time;
67 unsigned long total_active_time;
68 struct mutex freq_mutex;
69 struct list_head gov_list;
70 struct sgxfreq_governor *gov;
71 struct mutex gov_mutex;
72 struct sgxfreq_sgx_data sgx_data;
73 struct device *dev;
74#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
75 struct gpu_platform_data *pdata;
76#else
77 struct clk *core_clk;
78 struct clk *gpu_clk;
79 struct clk *per_clk;
80 struct clk *gpu_core_clk;
81 struct clk *gpu_hyd_clk;
82#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
83 struct regulator *gpu_reg;
84#endif
85#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
86 struct notifier_block *clk_nb;
87#endif
88#endif
89} sfd;
90
91/* Governor init/deinit functions */
92int onoff_init(void);
93int onoff_deinit(void);
94int activeidle_init(void);
95int activeidle_deinit(void);
96int on3demand_init(void);
97int on3demand_deinit(void);
98int userspace_init(void);
99int userspace_deinit(void);
100
101
102typedef int sgxfreq_gov_init_t(void);
103sgxfreq_gov_init_t *sgxfreq_gov_init[] = {
104 onoff_init,
105 activeidle_init,
106 on3demand_init,
107 userspace_init,
108 NULL,
109};
110
111typedef int sgxfreq_gov_deinit_t(void);
112sgxfreq_gov_deinit_t *sgxfreq_gov_deinit[] = {
113 onoff_deinit,
114 activeidle_deinit,
115 on3demand_deinit,
116 userspace_deinit,
117 NULL,
118};
119
120#define SGXFREQ_DEFAULT_GOV_NAME "on3demand"
121static unsigned long _idle_curr_time;
122static unsigned long _idle_prev_time;
123static unsigned long _active_curr_time;
124static unsigned long _active_prev_time;
125
126#if (defined(CONFIG_THERMAL) || defined(CONFIG_THERMAL_FRAMEWORK))
127int cool_init(void);
128void cool_deinit(void);
129#endif
130
131/*********************** begin sysfs interface ***********************/
132
133struct kobject *sgxfreq_kobj;
134
135static ssize_t show_frequency_list(struct device *dev,
136 struct device_attribute *attr,
137 char *buf)
138{
139 int i;
140 ssize_t count = 0;
141
142 for (i = 0; i < sfd.freq_cnt; i++)
143 count += sprintf(&buf[count], "%lu ", sfd.freq_list[i]);
144 count += sprintf(&buf[count], "\n");
145
146 return count;
147}
148
149static ssize_t show_frequency_request(struct device *dev,
150 struct device_attribute *attr,
151 char *buf)
152{
153 return sprintf(buf, "%lu\n", sfd.freq_request);
154}
155
156static ssize_t show_frequency_limit(struct device *dev,
157 struct device_attribute *attr,
158 char *buf)
159{
160 return sprintf(buf, "%lu\n", sfd.freq_limit);
161}
162
163static ssize_t show_frequency(struct device *dev,
164 struct device_attribute *attr,
165 char *buf)
166{
167 return sprintf(buf, "%lu\n", sfd.freq);
168}
169
170static ssize_t show_stat(struct device *dev,
171 struct device_attribute *attr,
172 char *buf)
173{
174 return sprintf(buf, "gpu %lu %lu\n",
175 sfd.total_active_time, sfd.total_idle_time);
176}
177
178static ssize_t show_governor_list(struct device *dev,
179 struct device_attribute *attr,
180 char *buf)
181{
182 ssize_t i = 0;
183 struct sgxfreq_governor *t;
184
185 list_for_each_entry(t, &sfd.gov_list, governor_list) {
186 if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
187 - (SGXFREQ_NAME_LEN + 2)))
188 goto out;
189 i += scnprintf(&buf[i], SGXFREQ_NAME_LEN, "%s ", t->name);
190 }
191out:
192 i += sprintf(&buf[i], "\n");
193 return i;
194}
195
196static ssize_t show_governor(struct device *dev,
197 struct device_attribute *attr, char *buf)
198{
199 if (sfd.gov)
200 return scnprintf(buf, SGXFREQ_NAME_LEN, "%s\n", sfd.gov->name);
201
202 return sprintf(buf, "\n");
203}
204
205static ssize_t store_governor(struct device *dev,
206 struct device_attribute *attr, const char *buf,
207 size_t count)
208{
209 int ret;
210 char name[16];
211
212 ret = sscanf(buf, "%15s", name);
213 if (ret != 1)
214 return -EINVAL;
215
216 ret = sgxfreq_set_governor(name);
217 if (ret)
218 return ret;
219 else
220 return count;
221}
222
223static DEVICE_ATTR(frequency_list, 0444, show_frequency_list, NULL);
224static DEVICE_ATTR(frequency_request, 0444, show_frequency_request, NULL);
225static DEVICE_ATTR(frequency_limit, 0444, show_frequency_limit, NULL);
226static DEVICE_ATTR(frequency, 0444, show_frequency, NULL);
227static DEVICE_ATTR(governor_list, 0444, show_governor_list, NULL);
228static DEVICE_ATTR(governor, 0644, show_governor, store_governor);
229static DEVICE_ATTR(stat, 0444, show_stat, NULL);
230
231static const struct attribute *sgxfreq_attributes[] = {
232 &dev_attr_frequency_list.attr,
233 &dev_attr_frequency_request.attr,
234 &dev_attr_frequency_limit.attr,
235 &dev_attr_frequency.attr,
236 &dev_attr_governor_list.attr,
237 &dev_attr_governor.attr,
238 &dev_attr_stat.attr,
239 NULL
240};
241
242/************************ end sysfs interface ************************/
243#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
244static int set_volt_for_freq(unsigned long freq)
245{
246 struct opp *opp;
247 unsigned long volt = 0;
248 int ret;
249
250 if (sfd.gpu_reg) {
251 opp = opp_find_freq_exact(sfd.dev, freq, true);
252 if(IS_ERR(opp))
253 {
254 int r = PTR_ERR(opp);
255 pr_err("sgxfreq: Couldn't find opp matching freq: %lu. Err: %d",
256 freq, r);
257 return -1;
258 }
259
260 volt = opp_get_voltage(opp);
261 if (!volt)
262 {
263 pr_err("sgxfreq: Could find volt corresponding to freq: %lu\n",
264 freq);
265 return -1;
266 }
267
268 ret = regulator_set_voltage_tol(sfd.gpu_reg, volt , 6000);
269 if (ret) {
270 pr_err("sgxfreq: Error(%d) setting volt: %lu for freq:%lu\n",
271 ret, volt, freq);
272 return ret;
273 }
274 }
275
276 return 0;
277
278}
279#endif
280
281static int __set_freq(void)
282{
283 unsigned long freq;
284 int ret = 0;
285
286 freq = min(sfd.freq_request, sfd.freq_limit);
287 if (freq != sfd.freq) {
288#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0))
289#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
290 if (freq > sfd.freq) {
291 /* Going up - must scale voltage before clocks */
292 if (set_volt_for_freq(freq) != 0) {
293 pr_err("sgxfreq: Error setting voltage for freq: %lu\n",
294 freq);
295 goto err1;
296 }
297 }
298#endif
299
300 ret = clk_set_rate(sfd.gpu_core_clk, freq);
301 if (ret) {
302 pr_err("sgxfreq: Error(%d) setting gpu core clock rate: %lu\n",
303 ret, freq);
304 goto err2;
305 }
306
307 ret = clk_set_rate(sfd.gpu_hyd_clk, freq);
308 if (ret) {
309 pr_err("sgxfreq: Error(%d) setting gpu hyd clock rate: %lu\n",
310 ret, freq);
311 goto err3;
312 }
313
314#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
315 if (freq < sfd.freq) {
316 /* Going down - must scale voltage after clocks */
317 if(set_volt_for_freq(freq) != 0) {
318 pr_err("sgxfreq: Error setting voltage for freq: %lu\n",
319 freq);
320 goto err4;
321 }
322 }
323#endif
324#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
325 sfd.pdata->device_scale(sfd.dev, sfd.dev, freq);
326#else
327 sfd.pdata->device_scale(sfd.dev, freq);
328#endif
329 sfd.freq = freq;
330
331 goto noerr;
332
333#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0))
334#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
335err4:
336#endif
337 ret |= clk_set_rate(sfd.gpu_hyd_clk, sfd.freq);
338
339err3:
340 ret |= clk_set_rate(sfd.gpu_core_clk, sfd.freq);
341err2:
342#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
343 if(freq > sfd.freq)
344 ret |= set_volt_for_freq(sfd.freq);
345err1:
346#endif
347#endif
348noerr:
349 return ret;
350 }
351 return ret;
352}
353
354static struct sgxfreq_governor *__find_governor(const char *name)
355{
356 struct sgxfreq_governor *t;
357
358 list_for_each_entry(t, &sfd.gov_list, governor_list)
359 if (!strncasecmp(name, t->name, SGXFREQ_NAME_LEN))
360 return t;
361
362 return NULL;
363}
364
365static void __update_timing_info(bool active)
366{
367 struct timeval tv;
368 do_gettimeofday(&tv);
369 if(active)
370 {
371 if(sfd.sgx_data.active == true) {
372 _active_curr_time = __tv2msec(tv);
373 sfd.total_active_time += __delta32(
374 _active_curr_time, _active_prev_time);
375 SGXFREQ_TRACE("A->A TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n",
376 sfd.total_active_time,
377 __delta32(_active_curr_time, _active_prev_time),
378 sfd.total_active_time,
379 (unsigned long)0);
380 _active_prev_time = _active_curr_time;
381 } else {
382 _idle_curr_time = __tv2msec(tv);
383 _active_prev_time = _idle_curr_time;
384 sfd.total_idle_time +=
385 __delta32(_idle_curr_time, _idle_prev_time);
386 SGXFREQ_TRACE("I->A TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n",
387 sfd.total_active_time,
388 (unsigned long)0,
389 sfd.total_idle_time,
390 __delta32(_idle_curr_time, _idle_prev_time));
391 }
392 } else {
393 if(sfd.sgx_data.active == true)
394 {
395 _idle_prev_time = _active_curr_time = __tv2msec(tv);
396 sfd.total_active_time +=
397 __delta32(_active_curr_time, _active_prev_time);
398 SGXFREQ_TRACE("A->I TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n",
399 sfd.total_active_time,
400 __delta32(_active_curr_time, _active_prev_time),
401 sfd.total_active_time,
402 (unsigned long)0);
403 }
404 else
405 {
406 _idle_curr_time = __tv2msec(tv);
407 sfd.total_idle_time += __delta32(
408 _idle_curr_time, _idle_prev_time);
409 SGXFREQ_TRACE("I->I TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n",
410 sfd.total_active_time,
411 (unsigned long)0,
412 sfd.total_idle_time,
413 __delta32(_idle_curr_time, _idle_prev_time));
414 _idle_prev_time = _idle_curr_time;
415 }
416 }
417}
418
419int sgxfreq_init(struct device *dev)
420{
421 int i, ret;
422 unsigned long freq;
423#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
424 struct dev_pm_opp *opp;
425 struct device_node *np;
426 unsigned int voltage_latency;
427#else
428 struct opp *opp;
429#endif
430 struct timeval tv;
431
432 sfd.dev = dev;
433 if (!sfd.dev)
434 return -EINVAL;
435#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
436 sfd.pdata = (struct gpu_platform_data *)dev->platform_data;
437 if (!sfd.pdata ||
438 !sfd.pdata->opp_get_opp_count ||
439 !sfd.pdata->opp_find_freq_ceil ||
440 !sfd.pdata->device_scale)
441 return -EINVAL;
442#endif
443
444 rcu_read_lock();
445
446#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
447 sfd.freq_cnt = sfd.pdata->opp_get_opp_count(dev);
448#else
449 ret = of_init_opp_table(dev);
450 if (ret) {
451 pr_err("sgxfreq: failed to init OPP table: %d\n", ret);
452 return -EINVAL;
453 }
454#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
455 sfd.freq_cnt = opp_get_opp_count(dev);
456#else
457 sfd.freq_cnt = dev_pm_opp_get_opp_count(dev);
458#endif
459#endif
460 if (sfd.freq_cnt < 1) {
461 pr_err("sgxfreq: failed to get operating frequencies\n");
462 rcu_read_unlock();
463 return -ENODEV;
464 }
465
466#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
467 np = of_node_get(dev->of_node);
468 sfd.clk_nb = of_pm_voltdm_notifier_register(dev, np, sfd.gpu_core_clk, "gpu",
469 &voltage_latency);
470
471 if (IS_ERR(sfd.clk_nb)) {
472 ret = PTR_ERR(sfd.clk_nb);
473 /* defer probe if regulator is not yet registered */
474 if (ret == -EPROBE_DEFER) {
475 dev_err(dev,
476 "gpu clock notifier not ready, retry\n");
477 } else {
478 dev_err(dev,
479 "Failed to register gpu clock notifier: %d\n",
480 ret);
481 }
482 return ret;
483 }
484
485#endif
486 sfd.freq_list = kmalloc(sfd.freq_cnt * sizeof(unsigned long), GFP_ATOMIC);
487 if (!sfd.freq_list) {
488 rcu_read_unlock();
489 return -ENOMEM;
490 }
491
492 freq = 0;
493 for (i = 0; i < sfd.freq_cnt; i++) {
494#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
495 opp = sfd.pdata->opp_find_freq_ceil(dev, &freq);
496#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
497 opp = opp_find_freq_ceil(dev, &freq);
498#else
499 /* 3.14 and later kernels */
500 opp = dev_pm_opp_find_freq_ceil(dev, &freq);
501#endif
502 if (IS_ERR_OR_NULL(opp)) {
503 rcu_read_unlock();
504 kfree(sfd.freq_list);
505 return -ENODEV;
506 }
507 sfd.freq_list[i] = freq;
508 freq++;
509 }
510 rcu_read_unlock();
511
512#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0))
513 sfd.core_clk = devm_clk_get(dev, "dpll_core_h14x2_ck");
514 if (IS_ERR(sfd.core_clk)) {
515 ret = PTR_ERR(sfd.core_clk);
516 pr_err("sgxfreq: failed to get core clock: %d\n", ret);
517 return ret;
518 }
519
520 sfd.gpu_clk = devm_clk_get(dev, "dpll_gpu_m2_ck");
521 if (IS_ERR(sfd.gpu_clk)) {
522 ret = PTR_ERR(sfd.gpu_clk);
523 pr_err("sgxfreq: failed to get gpu clock: %d\n", ret);
524 return ret;
525 }
526
527 sfd.per_clk = devm_clk_get(dev, "dpll_per_h14x2_ck");
528 if (IS_ERR(sfd.per_clk)) {
529 ret = PTR_ERR(sfd.per_clk);
530 pr_err("sgxfreq: failed to get per clock: %d\n", ret);
531 return ret;
532 }
533
534 sfd.gpu_core_clk = devm_clk_get(dev, "gpu_core_gclk_mux");
535 if (IS_ERR(sfd.gpu_core_clk)) {
536 ret = PTR_ERR(sfd.gpu_core_clk);
537 pr_err("sgxfreq: failed to get gpu core clock: %d\n", ret);
538 return ret;
539 }
540
541 sfd.gpu_hyd_clk = devm_clk_get(dev, "gpu_core_gclk_mux");
542 if (IS_ERR(sfd.gpu_hyd_clk)) {
543 ret = PTR_ERR(sfd.gpu_hyd_clk);
544 pr_err("sgxfreq: failed to get gpu hyd clock: %d\n", ret);
545 return ret;
546 }
547
548
549#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0))
550 sfd.gpu_reg = devm_regulator_get(dev, "gpu");
551 if (IS_ERR(sfd.gpu_reg)) {
552 if (PTR_ERR(sfd.gpu_reg) == -EPROBE_DEFER) {
553 dev_err(dev, "gpu regulator not ready, retry\n");
554 return -EPROBE_DEFER;
555 }
556 pr_err("sgxfreq: failed to get gpu regulator: %ld\n", PTR_ERR(sfd.gpu_reg));
557 sfd.gpu_reg = NULL;
558 }
559#endif
560
561 ret = clk_set_parent(sfd.gpu_hyd_clk, sfd.core_clk);
562 if (ret != 0) {
563 pr_err("sgxfreq: failed to set gpu_hyd_clk parent: %d\n", ret);
564 }
565
566 ret = clk_set_parent(sfd.gpu_core_clk, sfd.core_clk);
567 if (ret != 0) {
568 pr_err("sgxfreq: failed to set gpu_core_clk parent: %d\n", ret);
569 }
570#endif
571
572 mutex_init(&sfd.freq_mutex);
573 sfd.freq_limit = sfd.freq_list[sfd.freq_cnt - 1];
574 sgxfreq_set_freq_request(sfd.freq_list[sfd.freq_cnt - 1]);
575 sfd.sgx_data.clk_on = false;
576 sfd.sgx_data.active = false;
577
578 mutex_init(&sfd.gov_mutex);
579 INIT_LIST_HEAD(&sfd.gov_list);
580
581 sgxfreq_kobj = kobject_create_and_add("sgxfreq", &sfd.dev->kobj);
582 ret = sysfs_create_files(sgxfreq_kobj, sgxfreq_attributes);
583 if (ret) {
584 kfree(sfd.freq_list);
585 return ret;
586 }
587
588#if (defined(CONFIG_THERMAL) || defined(CONFIG_THERMAL_FRAMEWORK))
589 cool_init();
590#endif
591
592 for (i = 0; sgxfreq_gov_init[i] != NULL; i++)
593 sgxfreq_gov_init[i]();
594
595 if (sgxfreq_set_governor(SGXFREQ_DEFAULT_GOV_NAME)) {
596 kfree(sfd.freq_list);
597 return -ENODEV;
598 }
599 do_gettimeofday(&tv);
600 _idle_prev_time = _active_curr_time = _idle_curr_time =
601 _active_prev_time = __tv2msec(tv);
602
603 return 0;
604}
605
606int sgxfreq_deinit(void)
607{
608 int i;
609
610 sgxfreq_set_governor(NULL);
611
612 sgxfreq_set_freq_request(sfd.freq_list[0]);
613
614#if (defined(CONFIG_THERMAL) || defined(CONFIG_THERMAL_FRAMEWORK))
615 cool_deinit();
616#endif
617
618 for (i = 0; sgxfreq_gov_deinit[i] != NULL; i++)
619 sgxfreq_gov_deinit[i]();
620
621 sysfs_remove_files(sgxfreq_kobj, sgxfreq_attributes);
622 kobject_put(sgxfreq_kobj);
623
624 kfree(sfd.freq_list);
625
626 return 0;
627}
628
629int sgxfreq_register_governor(struct sgxfreq_governor *governor)
630{
631 if (!governor)
632 return -EINVAL;
633
634 list_add(&governor->governor_list, &sfd.gov_list);
635
636 return 0;
637}
638
639void sgxfreq_unregister_governor(struct sgxfreq_governor *governor)
640{
641 if (!governor)
642 return;
643
644 list_del(&governor->governor_list);
645}
646
647int sgxfreq_set_governor(const char *name)
648{
649 int ret = 0;
650 struct sgxfreq_governor *new_gov = 0;
651
652 if (name) {
653 new_gov = __find_governor(name);
654 if (!new_gov)
655 return -EINVAL;
656 }
657
658 mutex_lock(&sfd.gov_mutex);
659
660 if (sfd.gov && sfd.gov->gov_stop)
661 sfd.gov->gov_stop();
662
663 if (new_gov && new_gov->gov_start)
664 ret = new_gov->gov_start(&sfd.sgx_data);
665
666 if (ret) {
667 if (sfd.gov && sfd.gov->gov_start)
668 sfd.gov->gov_start(&sfd.sgx_data);
669 return -ENODEV;
670 }
671 sfd.gov = new_gov;
672
673 mutex_unlock(&sfd.gov_mutex);
674
675 return 0;
676}
677
678int sgxfreq_get_freq_list(unsigned long **pfreq_list)
679{
680 *pfreq_list = sfd.freq_list;
681
682 return sfd.freq_cnt;
683}
684
685unsigned long sgxfreq_get_freq_min(void)
686{
687 return sfd.freq_list[0];
688}
689
690unsigned long sgxfreq_get_freq_max(void)
691{
692 return sfd.freq_list[sfd.freq_cnt - 1];
693}
694
695unsigned long sgxfreq_get_freq_floor(unsigned long freq)
696{
697 int i;
698 unsigned long f = 0;
699
700 for (i = sfd.freq_cnt - 1; i >= 0; i--) {
701 f = sfd.freq_list[i];
702 if (f <= freq)
703 return f;
704 }
705
706 return f;
707}
708
709unsigned long sgxfreq_get_freq_ceil(unsigned long freq)
710{
711 int i;
712 unsigned long f = 0;
713
714 for (i = 0; i < sfd.freq_cnt; i++) {
715 f = sfd.freq_list[i];
716 if (f >= freq)
717 return f;
718 }
719
720 return f;
721}
722
723unsigned long sgxfreq_get_freq(void)
724{
725 return sfd.freq;
726}
727
728unsigned long sgxfreq_get_freq_request(void)
729{
730 return sfd.freq_request;
731}
732
733unsigned long sgxfreq_get_freq_limit(void)
734{
735 return sfd.freq_limit;
736}
737
738unsigned long sgxfreq_set_freq_request(unsigned long freq_request)
739{
740 freq_request = sgxfreq_get_freq_ceil(freq_request);
741
742 mutex_lock(&sfd.freq_mutex);
743
744 sfd.freq_request = freq_request;
745 __set_freq();
746
747 mutex_unlock(&sfd.freq_mutex);
748
749 return freq_request;
750}
751
752unsigned long sgxfreq_set_freq_limit(unsigned long freq_limit)
753{
754 freq_limit = sgxfreq_get_freq_ceil(freq_limit);
755
756 mutex_lock(&sfd.freq_mutex);
757
758 sfd.freq_limit = freq_limit;
759 __set_freq();
760
761 mutex_unlock(&sfd.freq_mutex);
762
763 return freq_limit;
764}
765
766unsigned long sgxfreq_get_total_active_time(void)
767{
768 __update_timing_info(sfd.sgx_data.active);
769 return sfd.total_active_time;
770}
771
772unsigned long sgxfreq_get_total_idle_time(void)
773{
774 __update_timing_info(sfd.sgx_data.active);
775 return sfd.total_idle_time;
776}
777
778/*
779 * sgx_clk_on, sgx_clk_off, sgx_active, and sgx_idle notifications are
780 * serialized by power lock. governor notif calls need sync with governor
781 * setting.
782 */
783void sgxfreq_notif_sgx_clk_on(void)
784{
785 sfd.sgx_data.clk_on = true;
786
787 mutex_lock(&sfd.gov_mutex);
788
789 if (sfd.gov && sfd.gov->sgx_clk_on)
790 sfd.gov->sgx_clk_on();
791
792 mutex_unlock(&sfd.gov_mutex);
793}
794
795void sgxfreq_notif_sgx_clk_off(void)
796{
797 sfd.sgx_data.clk_on = false;
798
799 mutex_lock(&sfd.gov_mutex);
800
801 if (sfd.gov && sfd.gov->sgx_clk_off)
802 sfd.gov->sgx_clk_off();
803
804 mutex_unlock(&sfd.gov_mutex);
805}
806
807
808void sgxfreq_notif_sgx_active(void)
809{
810 __update_timing_info(true);
811
812 sfd.sgx_data.active = true;
813
814 mutex_lock(&sfd.gov_mutex);
815
816 if (sfd.gov && sfd.gov->sgx_active)
817 sfd.gov->sgx_active();
818
819 mutex_unlock(&sfd.gov_mutex);
820
821}
822
823void sgxfreq_notif_sgx_idle(void)
824{
825
826 __update_timing_info(false);
827
828 sfd.sgx_data.active = false;
829
830 mutex_lock(&sfd.gov_mutex);
831
832 if (sfd.gov && sfd.gov->sgx_idle)
833 sfd.gov->sgx_idle();
834
835 mutex_unlock(&sfd.gov_mutex);
836}
837
838void sgxfreq_notif_sgx_frame_done(void)
839{
840 mutex_lock(&sfd.gov_mutex);
841
842 if (sfd.gov && sfd.gov->sgx_frame_done)
843 sfd.gov->sgx_frame_done();
844
845 mutex_unlock(&sfd.gov_mutex);
846}