Merge commit 'main-jb-2012.08.03-B4' into t114-0806
[linux-2.6.git] / drivers / video / tegra / host / gr3d / scale3d.c
1 /*
2  * drivers/video/tegra/host/t20/scale3d.c
3  *
4  * Tegra Graphics Host 3D clock scaling
5  *
6  * Copyright (c) 2010-2012, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /*
22  * 3d clock scaling
23  *
24  * module3d_notify_busy() is called upon submit, module3d_notify_idle() is
25  * called when all outstanding submits are completed. Idle times are measured
26  * over a fixed time period (scale3d.p_period). If the 3d module idle time
27  * percentage goes over the limit (set in scale3d.p_idle_max), 3d clocks are
28  * scaled down. If the percentage goes under the minimum limit (set in
29  * scale3d.p_idle_min), 3d clocks are scaled up. An additional test is made
30  * over the time frame given in scale3d.p_fast_response for clocking up
31  * quickly in response to load peaks.
32  *
33  * 3d.emc clock is scaled proportionately to 3d clock, with a quadratic-
34  * bezier-like factor added to pull 3d.emc rate a bit lower.
35  */
36
37 #include <linux/debugfs.h>
38 #include <linux/types.h>
39 #include <linux/clk.h>
40 #include <mach/clk.h>
41 #include <mach/hardware.h>
42 #include "scale3d.h"
43 #include "dev.h"
44
45 static int scale3d_is_enabled(void);
46 static void scale3d_enable(int enable);
47
48 #define POW2(x) ((x) * (x))
49
50 /*
51  * debugfs parameters to control 3d clock scaling test
52  *
53  * period        - time period for clock rate evaluation
54  * fast_response - time period for evaluation of 'busy' spikes
55  * idle_min      - if less than [idle_min] percent idle over [fast_response]
56  *                 microseconds, clock up.
57  * idle_max      - if over [idle_max] percent idle over [period] microseconds,
58  *                 clock down.
59  * max_scale     - limits rate changes to no less than (100 - max_scale)% or
60  *                 (100 + 2 * max_scale)% of current clock rate
61  * verbosity     - set above 5 for debug printouts
62  */
63
64 struct scale3d_info_rec {
65         struct mutex lock; /* lock for timestamps etc */
66         int enable;
67         int init;
68         ktime_t idle_frame;
69         ktime_t fast_frame;
70         ktime_t last_idle;
71         ktime_t last_short_term_idle;
72         int is_idle;
73         ktime_t last_tweak;
74         ktime_t last_down;
75         int fast_up_count;
76         int slow_down_count;
77         int is_scaled;
78         int fast_responses;
79         unsigned long idle_total;
80         unsigned long idle_short_term_total;
81         unsigned long max_rate_3d;
82         long emc_slope;
83         long emc_offset;
84         long emc_dip_slope;
85         long emc_dip_offset;
86         long emc_xmid;
87         unsigned long min_rate_3d;
88         ktime_t last_throughput_hint;
89         struct work_struct work;
90         struct delayed_work idle_timer;
91         unsigned int scale;
92         unsigned int p_use_throughput_hint;
93         unsigned int p_throughput_lo_limit;
94         unsigned int p_throughput_hi_limit;
95         unsigned int p_scale_step;
96         unsigned int p_period;
97         unsigned int period;
98         unsigned int p_idle_min;
99         unsigned int idle_min;
100         unsigned int p_idle_max;
101         unsigned int idle_max;
102         unsigned int p_fast_response;
103         unsigned int fast_response;
104         unsigned int p_adjust;
105         unsigned int p_scale_emc;
106         unsigned int p_emc_dip;
107         unsigned int p_verbosity;
108         struct clk *clk_3d;
109         struct clk *clk_3d2;
110         struct clk *clk_3d_emc;
111 };
112
113 static struct scale3d_info_rec scale3d;
114
115 static void scale3d_clocks(unsigned long percent)
116 {
117         unsigned long hz, curr;
118
119         if (!tegra_is_clk_enabled(scale3d.clk_3d))
120                 return;
121
122         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
123                 if (!tegra_is_clk_enabled(scale3d.clk_3d2))
124                         return;
125
126         curr = clk_get_rate(scale3d.clk_3d);
127         hz = percent * (curr / 100);
128
129         if (!(hz >= scale3d.max_rate_3d && curr == scale3d.max_rate_3d)) {
130                 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
131                         clk_set_rate(scale3d.clk_3d2, 0);
132                 clk_set_rate(scale3d.clk_3d, hz);
133
134                 if (scale3d.p_scale_emc) {
135                         long after = (long) clk_get_rate(scale3d.clk_3d);
136                         hz = after * scale3d.emc_slope + scale3d.emc_offset;
137                         if (scale3d.p_emc_dip)
138                                 hz -=
139                                         (scale3d.emc_dip_slope *
140                                         POW2(after / 1000 - scale3d.emc_xmid) +
141                                         scale3d.emc_dip_offset);
142                         clk_set_rate(scale3d.clk_3d_emc, hz);
143                 }
144         }
145 }
146
147 static void scale3d_clocks_handler(struct work_struct *work)
148 {
149         unsigned int scale;
150
151         mutex_lock(&scale3d.lock);
152         scale = scale3d.scale;
153         mutex_unlock(&scale3d.lock);
154
155         if (scale != 0)
156                 scale3d_clocks(scale);
157 }
158
159 void nvhost_scale3d_suspend(struct nvhost_device *dev)
160 {
161         if (!scale3d.enable)
162                 return;
163
164         cancel_work_sync(&scale3d.work);
165         cancel_delayed_work(&scale3d.idle_timer);
166 }
167
168 /* set 3d clocks to max */
169 static void reset_3d_clocks(void)
170 {
171         if (clk_get_rate(scale3d.clk_3d) != scale3d.max_rate_3d) {
172                 clk_set_rate(scale3d.clk_3d, scale3d.max_rate_3d);
173                 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
174                         clk_set_rate(scale3d.clk_3d2, scale3d.max_rate_3d);
175                 if (scale3d.p_scale_emc)
176                         clk_set_rate(scale3d.clk_3d_emc,
177                                 clk_round_rate(scale3d.clk_3d_emc, UINT_MAX));
178         }
179 }
180
181 static int scale3d_is_enabled(void)
182 {
183         int enable;
184
185         if (!scale3d.enable)
186                 return 0;
187
188         mutex_lock(&scale3d.lock);
189         enable = scale3d.enable;
190         mutex_unlock(&scale3d.lock);
191
192         return enable;
193 }
194
195 static void scale3d_enable(int enable)
196 {
197         int disable = 0;
198
199         mutex_lock(&scale3d.lock);
200
201         if (enable) {
202                 if (scale3d.max_rate_3d != scale3d.min_rate_3d)
203                         scale3d.enable = 1;
204         } else {
205                 scale3d.enable = 0;
206                 disable = 1;
207         }
208
209         mutex_unlock(&scale3d.lock);
210
211         if (disable)
212                 reset_3d_clocks();
213 }
214
215 static void reset_scaling_counters(ktime_t time)
216 {
217         scale3d.idle_total = 0;
218         scale3d.idle_short_term_total = 0;
219         scale3d.last_idle = time;
220         scale3d.last_short_term_idle = time;
221         scale3d.idle_frame = time;
222 }
223
224 /* scaling_adjust - use scale up / scale down hint counts to adjust scaling
225  * parameters.
226  *
227  * hint_ratio is 100 x the ratio of scale up to scale down hints. Three cases
228  * are distinguished:
229  *
230  * hint_ratio < HINT_RATIO_MIN - set parameters to maximize scaling effect
231  * hint_ratio > HINT_RATIO_MAX - set parameters to minimize scaling effect
232  * hint_ratio between limits - scale parameters linearly
233  *
234  * the parameters adjusted are
235  *
236  * * fast_response time
237  * * period - time for scaling down estimate
238  * * idle_min percentage
239  * * idle_max percentage
240  */
241 #define SCALING_ADJUST_PERIOD 1000000
242 #define HINT_RATIO_MAX 400
243 #define HINT_RATIO_MIN 100
244 #define HINT_RATIO_MID ((HINT_RATIO_MAX + HINT_RATIO_MIN) / 2)
245 #define HINT_RATIO_DIFF (HINT_RATIO_MAX - HINT_RATIO_MIN)
246
247 static void scaling_adjust(ktime_t time)
248 {
249         long hint_ratio;
250         long fast_response_adjustment;
251         long period_adjustment;
252         int idle_min_adjustment;
253         int idle_max_adjustment;
254         unsigned long dt;
255
256         dt = (unsigned long) ktime_us_delta(time, scale3d.last_tweak);
257         if (dt < SCALING_ADJUST_PERIOD)
258                 return;
259
260         hint_ratio = (100 * (scale3d.fast_up_count + 1)) /
261                                  (scale3d.slow_down_count + 1);
262
263         if (hint_ratio > HINT_RATIO_MAX) {
264                 fast_response_adjustment = -((int) scale3d.p_fast_response) / 4;
265                 period_adjustment = scale3d.p_period / 2;
266                 idle_min_adjustment = scale3d.p_idle_min;
267                 idle_max_adjustment = scale3d.p_idle_max;
268         } else if (hint_ratio < HINT_RATIO_MIN) {
269                 fast_response_adjustment = scale3d.p_fast_response / 2;
270                 period_adjustment = -((int) scale3d.p_period) / 4;
271                 idle_min_adjustment = -((int) scale3d.p_idle_min) / 2;
272                 idle_max_adjustment = -((int) scale3d.p_idle_max) / 2;
273         } else {
274                 int diff;
275                 int factor;
276
277                 diff = HINT_RATIO_MID - hint_ratio;
278                 if (diff < 0)
279                         factor = -diff * 2;
280                 else {
281                         factor = -diff;
282                         diff *= 2;
283                 }
284
285                 fast_response_adjustment = diff *
286                         (scale3d.p_fast_response / (HINT_RATIO_DIFF * 2));
287                 period_adjustment =
288                         diff * (scale3d.p_period / HINT_RATIO_DIFF);
289                 idle_min_adjustment =
290                         (factor * (int) scale3d.p_idle_min) / HINT_RATIO_DIFF;
291                 idle_max_adjustment =
292                         (factor * (int) scale3d.p_idle_max) / HINT_RATIO_DIFF;
293         }
294
295         scale3d.fast_response =
296                 scale3d.p_fast_response + fast_response_adjustment;
297         scale3d.period = scale3d.p_period + period_adjustment;
298                 scale3d.idle_min = scale3d.p_idle_min + idle_min_adjustment;
299         scale3d.idle_max = scale3d.p_idle_max + idle_max_adjustment;
300
301         if (scale3d.p_verbosity >= 10)
302                 pr_info("scale3d stats: + %d - %d (/ %d) f %u p %u min %u max %u\n",
303                         scale3d.fast_up_count, scale3d.slow_down_count,
304                         scale3d.fast_responses, scale3d.fast_response,
305                         scale3d.period, scale3d.idle_min, scale3d.idle_max);
306
307         scale3d.fast_up_count = 0;
308         scale3d.slow_down_count = 0;
309         scale3d.fast_responses = 0;
310         scale3d.last_down = time;
311         scale3d.last_tweak = time;
312 }
313
314 #undef SCALING_ADJUST_PERIOD
315 #undef HINT_RATIO_MAX
316 #undef HINT_RATIO_MIN
317 #undef HINT_RATIO_MID
318 #undef HINT_RATIO_DIFF
319
320 static void scaling_state_check(ktime_t time)
321 {
322         unsigned long dt;
323
324         /* adjustment: set scale parameters (fast_response, period) +/- 25%
325          * based on ratio of scale up to scale down hints
326          */
327         if (scale3d.p_adjust)
328                 scaling_adjust(time);
329         else {
330                 scale3d.fast_response = scale3d.p_fast_response;
331                 scale3d.period = scale3d.p_period;
332                 scale3d.idle_min = scale3d.p_idle_min;
333                 scale3d.idle_max = scale3d.p_idle_max;
334         }
335
336         /* check for load peaks */
337         dt = (unsigned long) ktime_us_delta(time, scale3d.fast_frame);
338         if (dt > scale3d.fast_response) {
339                 unsigned long idleness =
340                         (scale3d.idle_short_term_total * 100) / dt;
341                 scale3d.fast_responses++;
342                 scale3d.fast_frame = time;
343                 /* if too busy, scale up */
344                 if (idleness < scale3d.idle_min) {
345                         scale3d.is_scaled = 0;
346                         scale3d.fast_up_count++;
347                         if (scale3d.p_verbosity >= 5)
348                                 pr_info("scale3d: %ld%% busy\n",
349                                         100 - idleness);
350
351                         reset_3d_clocks();
352                         reset_scaling_counters(time);
353                         return;
354                 }
355                 scale3d.idle_short_term_total = 0;
356                 scale3d.last_short_term_idle = time;
357         }
358
359         dt = (unsigned long) ktime_us_delta(time, scale3d.idle_frame);
360         if (dt > scale3d.period) {
361                 unsigned long idleness = (scale3d.idle_total * 100) / dt;
362
363                 if (scale3d.p_verbosity >= 5)
364                         pr_info("scale3d: idle %lu, ~%lu%%\n",
365                                 scale3d.idle_total, idleness);
366
367                 if (idleness > scale3d.idle_max) {
368                         if (!scale3d.is_scaled) {
369                                 scale3d.is_scaled = 1;
370                                 scale3d.last_down = time;
371                         }
372                         scale3d.slow_down_count++;
373                         /* if idle time is high, clock down */
374                         scale3d.scale = 100 - (idleness - scale3d.idle_min);
375                         schedule_work(&scale3d.work);
376                 }
377
378                 reset_scaling_counters(time);
379         }
380 }
381
382 void nvhost_scale3d_notify_idle(struct nvhost_device *dev)
383 {
384         ktime_t t;
385         unsigned long dt;
386
387         if (!scale3d.enable)
388                 return;
389
390         /* if throughput hint enabled, and last hint is recent enough, return */
391         if (scale3d.p_use_throughput_hint) {
392                 t = ktime_get();
393                 if (ktime_us_delta(t, scale3d.last_throughput_hint) < 1000000)
394                         return;
395         }
396
397         mutex_lock(&scale3d.lock);
398
399         t = ktime_get();
400
401         if (scale3d.is_idle) {
402                 dt = ktime_us_delta(t, scale3d.last_idle);
403                 scale3d.idle_total += dt;
404                 dt = ktime_us_delta(t, scale3d.last_short_term_idle);
405                 scale3d.idle_short_term_total += dt;
406         } else
407                 scale3d.is_idle = 1;
408
409         scale3d.last_idle = t;
410         scale3d.last_short_term_idle = t;
411
412         scaling_state_check(scale3d.last_idle);
413
414         /* delay idle_max % of 2 * fast_response time (given in microseconds) */
415         schedule_delayed_work(&scale3d.idle_timer,
416                 msecs_to_jiffies((scale3d.idle_max * scale3d.fast_response)
417                         / 50000));
418
419         mutex_unlock(&scale3d.lock);
420 }
421
422 void nvhost_scale3d_notify_busy(struct nvhost_device *dev)
423 {
424         unsigned long idle;
425         unsigned long short_term_idle;
426         ktime_t t;
427
428         if (!scale3d.enable)
429                 return;
430
431         /* if throughput hint enabled, and last hint is recent enough, return */
432         if (scale3d.p_use_throughput_hint) {
433                 t = ktime_get();
434                 if (ktime_us_delta(t, scale3d.last_throughput_hint) < 1000000)
435                         return;
436         }
437
438         mutex_lock(&scale3d.lock);
439
440         cancel_delayed_work(&scale3d.idle_timer);
441
442         t = ktime_get();
443
444         if (scale3d.is_idle) {
445                 idle = (unsigned long)
446                         ktime_us_delta(t, scale3d.last_idle);
447                 scale3d.idle_total += idle;
448                 short_term_idle =
449                         ktime_us_delta(t, scale3d.last_short_term_idle);
450                 scale3d.idle_short_term_total += short_term_idle;
451                 scale3d.is_idle = 0;
452         }
453
454         scaling_state_check(t);
455
456         mutex_unlock(&scale3d.lock);
457 }
458
459 static void do_scale(int diff)
460 {
461         unsigned long hz, curr;
462
463         if (!tegra_is_clk_enabled(scale3d.clk_3d))
464                 return;
465
466         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
467                 if (!tegra_is_clk_enabled(scale3d.clk_3d2))
468                         return;
469
470         curr = clk_get_rate(scale3d.clk_3d);
471         hz = curr + diff;
472
473         if (hz < scale3d.min_rate_3d)
474                 hz = scale3d.min_rate_3d;
475
476         if (hz > scale3d.max_rate_3d)
477                 hz = scale3d.max_rate_3d;
478
479         if (hz == curr) return;
480
481         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
482                 clk_set_rate(scale3d.clk_3d2, 0);
483         clk_set_rate(scale3d.clk_3d, hz);
484
485         if (scale3d.p_scale_emc) {
486                 long after = (long) clk_get_rate(scale3d.clk_3d);
487                 hz = after * scale3d.emc_slope + scale3d.emc_offset;
488                 if (scale3d.p_emc_dip)
489                         hz -=
490                                 (scale3d.emc_dip_slope *
491                                 POW2(after / 1000 - scale3d.emc_xmid) +
492                                 scale3d.emc_dip_offset);
493                 clk_set_rate(scale3d.clk_3d_emc, hz);
494         }
495 }
496
497 #define scale_up() do_scale(scale3d.p_scale_step)
498 #define scale_down() do_scale(-scale3d.p_scale_step)
499
500 void nvhost_scale3d_set_throughput_hint(int hint)
501 {
502         if (!scale3d.enable)
503                 return;
504
505         if (!scale3d.p_use_throughput_hint)
506                 return;
507
508         scale3d.last_throughput_hint = ktime_get();
509
510         if (scale3d.p_use_throughput_hint) {
511                 if (hint >= scale3d.p_throughput_hi_limit)
512                         scale_down();
513                 else if (hint <= scale3d.p_throughput_lo_limit)
514                         scale_up();
515         }
516 }
517 EXPORT_SYMBOL(nvhost_scale3d_set_throughput_hint);
518
519 static void scale3d_idle_handler(struct work_struct *work)
520 {
521         int notify_idle = 0;
522
523         if (!scale3d.enable)
524                 return;
525
526         mutex_lock(&scale3d.lock);
527
528         if (scale3d.is_idle && tegra_is_clk_enabled(scale3d.clk_3d)) {
529                 unsigned long curr = clk_get_rate(scale3d.clk_3d);
530                 if (curr > scale3d.min_rate_3d)
531                         notify_idle = 1;
532         }
533
534         mutex_unlock(&scale3d.lock);
535
536         if (notify_idle)
537                 nvhost_scale3d_notify_idle(NULL);
538 }
539
540 void nvhost_scale3d_reset()
541 {
542         ktime_t t;
543
544         if (!scale3d.enable)
545                 return;
546
547         t = ktime_get();
548         mutex_lock(&scale3d.lock);
549         reset_scaling_counters(t);
550         mutex_unlock(&scale3d.lock);
551 }
552
553 /*
554  * debugfs parameters to control 3d clock scaling
555  */
556
557 void nvhost_scale3d_debug_init(struct dentry *de)
558 {
559         struct dentry *d, *f;
560
561         d = debugfs_create_dir("scaling", de);
562         if (!d) {
563                 pr_err("scale3d: can\'t create debugfs directory\n");
564                 return;
565         }
566
567 #define CREATE_SCALE3D_FILE(fname) \
568         do {\
569                 f = debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, d,\
570                         &scale3d.p_##fname);\
571                 if (NULL == f) {\
572                         pr_err("scale3d: can\'t create file " #fname "\n");\
573                         return;\
574                 } \
575         } while (0)
576
577         CREATE_SCALE3D_FILE(fast_response);
578         CREATE_SCALE3D_FILE(idle_min);
579         CREATE_SCALE3D_FILE(idle_max);
580         CREATE_SCALE3D_FILE(period);
581         CREATE_SCALE3D_FILE(adjust);
582         CREATE_SCALE3D_FILE(scale_emc);
583         CREATE_SCALE3D_FILE(emc_dip);
584         CREATE_SCALE3D_FILE(use_throughput_hint);
585         CREATE_SCALE3D_FILE(throughput_hi_limit);
586         CREATE_SCALE3D_FILE(throughput_lo_limit);
587         CREATE_SCALE3D_FILE(scale_step);
588         CREATE_SCALE3D_FILE(verbosity);
589 #undef CREATE_SCALE3D_FILE
590 }
591
592 static ssize_t enable_3d_scaling_show(struct device *device,
593         struct device_attribute *attr, char *buf)
594 {
595         ssize_t res;
596
597         res = snprintf(buf, PAGE_SIZE, "%d\n", scale3d_is_enabled());
598
599         return res;
600 }
601
602 static ssize_t enable_3d_scaling_store(struct device *dev,
603         struct device_attribute *attr, const char *buf, size_t count)
604 {
605         unsigned long val = 0;
606
607         if (strict_strtoul(buf, 10, &val) < 0)
608                 return -EINVAL;
609
610         scale3d_enable(val);
611
612         return count;
613 }
614
615 static DEVICE_ATTR(enable_3d_scaling, S_IRUGO | S_IWUSR,
616         enable_3d_scaling_show, enable_3d_scaling_store);
617
618 void nvhost_scale3d_init(struct nvhost_device *d)
619 {
620         if (!scale3d.init) {
621                 int error;
622                 unsigned long max_emc, min_emc;
623                 long correction;
624                 mutex_init(&scale3d.lock);
625
626                 INIT_WORK(&scale3d.work, scale3d_clocks_handler);
627                 INIT_DELAYED_WORK(&scale3d.idle_timer, scale3d_idle_handler);
628
629                 scale3d.clk_3d = d->clk[0];
630                 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) {
631                         scale3d.clk_3d2 = d->clk[1];
632                         scale3d.clk_3d_emc = d->clk[2];
633                 } else
634                         scale3d.clk_3d_emc = d->clk[1];
635
636                 scale3d.max_rate_3d = clk_round_rate(scale3d.clk_3d, UINT_MAX);
637                 scale3d.min_rate_3d = clk_round_rate(scale3d.clk_3d, 0);
638
639                 if (scale3d.max_rate_3d == scale3d.min_rate_3d) {
640                         pr_warn("scale3d: 3d max rate = min rate (%lu), "
641                                 "disabling\n", scale3d.max_rate_3d);
642                         scale3d.enable = 0;
643                         return;
644                 }
645
646                 /* emc scaling:
647                  *
648                  * Remc = S * R3d + O - (Sd * (R3d - Rm)^2 + Od)
649                  *
650                  * Remc - 3d.emc rate
651                  * R3d  - 3d.cbus rate
652                  * Rm   - 3d.cbus 'middle' rate = (max + min)/2
653                  * S    - emc_slope
654                  * O    - emc_offset
655                  * Sd   - emc_dip_slope
656                  * Od   - emc_dip_offset
657                  *
658                  * this superposes a quadratic dip centered around the middle 3d
659                  * frequency over a linear correlation of 3d.emc to 3d clock
660                  * rates.
661                  *
662                  * S, O are chosen so that the maximum 3d rate produces the
663                  * maximum 3d.emc rate exactly, and the minimum 3d rate produces
664                  * at least the minimum 3d.emc rate.
665                  *
666                  * Sd and Od are chosen to produce the largest dip that will
667                  * keep 3d.emc frequencies monotonously decreasing with 3d
668                  * frequencies. To achieve this, the first derivative of Remc
669                  * with respect to R3d should be zero for the minimal 3d rate:
670                  *
671                  *   R'emc = S - 2 * Sd * (R3d - Rm)
672                  *   R'emc(R3d-min) = 0
673                  *   S = 2 * Sd * (R3d-min - Rm)
674                  *     = 2 * Sd * (R3d-min - R3d-max) / 2
675                  *   Sd = S / (R3d-min - R3d-max)
676                  *
677                  *   +---------------------------------------------------+
678                  *   | Sd = -(emc-max - emc-min) / (R3d-min - R3d-max)^2 |
679                  *   +---------------------------------------------------+
680                  *
681                  *   dip = Sd * (R3d - Rm)^2 + Od
682                  *
683                  * requiring dip(R3d-min) = 0 and dip(R3d-max) = 0 gives
684                  *
685                  *   Sd * (R3d-min - Rm)^2 + Od = 0
686                  *   Od = -Sd * ((R3d-min - R3d-max) / 2)^2
687                  *      = -Sd * ((R3d-min - R3d-max)^2) / 4
688                  *
689                  *   +------------------------------+
690                  *   | Od = (emc-max - emc-min) / 4 |
691                  *   +------------------------------+
692                  */
693
694                 max_emc = clk_round_rate(scale3d.clk_3d_emc, UINT_MAX);
695                 min_emc = clk_round_rate(scale3d.clk_3d_emc, 0);
696
697                 scale3d.emc_slope = (max_emc - min_emc) /
698                          (scale3d.max_rate_3d - scale3d.min_rate_3d);
699                 scale3d.emc_offset = max_emc -
700                         scale3d.emc_slope * scale3d.max_rate_3d;
701                 /* guarantee max 3d rate maps to max emc rate */
702                 scale3d.emc_offset += max_emc -
703                         (scale3d.emc_slope * scale3d.max_rate_3d +
704                         scale3d.emc_offset);
705
706                 scale3d.emc_dip_offset = (max_emc - min_emc) / 4;
707                 scale3d.emc_dip_slope =
708                         -4 * (scale3d.emc_dip_offset /
709                         (POW2(scale3d.max_rate_3d - scale3d.min_rate_3d)));
710                 scale3d.emc_xmid =
711                         (scale3d.max_rate_3d + scale3d.min_rate_3d) / 2;
712                 correction =
713                         scale3d.emc_dip_offset +
714                                 scale3d.emc_dip_slope *
715                                 POW2(scale3d.max_rate_3d - scale3d.emc_xmid);
716                 scale3d.emc_dip_offset -= correction;
717
718                 /* set scaling parameter defaults */
719                 scale3d.enable = 1;
720                 scale3d.period = scale3d.p_period = 100000;
721                 scale3d.idle_min = scale3d.p_idle_min = 10;
722                 scale3d.idle_max = scale3d.p_idle_max = 15;
723                 scale3d.fast_response = scale3d.p_fast_response = 7000;
724                 scale3d.p_scale_emc = 1;
725                 scale3d.p_emc_dip = 1;
726                 scale3d.p_verbosity = 0;
727                 scale3d.p_adjust = 1;
728                 scale3d.p_use_throughput_hint = 1;
729                 scale3d.p_throughput_lo_limit = 95;
730                 scale3d.p_throughput_hi_limit = 100;
731                 scale3d.p_scale_step = 60000000;
732
733                 error = device_create_file(&d->dev,
734                                 &dev_attr_enable_3d_scaling);
735                 if (error)
736                         dev_err(&d->dev, "failed to create sysfs attributes");
737
738                 scale3d.init = 1;
739         }
740
741         nvhost_scale3d_reset();
742 }
743
744 void nvhost_scale3d_deinit(struct nvhost_device *dev)
745 {
746         device_remove_file(&dev->dev, &dev_attr_enable_3d_scaling);
747         scale3d.init = 0;
748 }