video: tegra: host: Move debugfs inits
[linux-3.10.git] / drivers / video / tegra / host / gr3d / scale3d_actmon.c
1 /*
2  * drivers/video/tegra/host/gr3d/scale3d_actmon.c
3  *
4  * Tegra Graphics Host 3D clock scaling
5  *
6  * Copyright (c) 2010-2013, NVIDIA Corporation. All rights reserved.
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 mechanism
23  *
24  * module3d_notify_busy() is called upon submit, module3d_notify_idle() is
25  * called when all outstanding submits are completed. Both functions notify
26  * the governor about changed state.
27  *
28  * 3d.emc clock is scaled proportionately to 3d clock, with a quadratic-
29  * bezier-like factor added to pull 3d.emc rate a bit lower.
30  */
31
32 #include <linux/devfreq.h>
33 #include <linux/debugfs.h>
34 #include <linux/types.h>
35 #include <linux/clk.h>
36 #include <linux/export.h>
37 #include <linux/slab.h>
38 #include <linux/platform_data/tegra_edp.h>
39
40 #include <chip_support.h>
41 #include <host1x/host1x.h>
42 #include <host1x/hw_host1x02_sync.h>
43
44 #include <mach/clk.h>
45 #include <mach/hardware.h>
46
47 #include <governor.h>
48
49 #include "pod_scaling.h"
50 #include "scale3d_actmon.h"
51 #include "dev.h"
52 #include "nvhost_acm.h"
53
54 #define POW2(x) ((x) * (x))
55
56 static int nvhost_scale3d_target(struct device *d, unsigned long *freq,
57                                         u32 flags);
58
59 /*******************************************************************************
60  * power_profile_rec - Device specific power management variables
61  ******************************************************************************/
62
63 struct power_profile_gr3d {
64
65         int                             init;
66
67         /*
68          * Use emc_slope and emc_dip_slope as unsigned fixed point<20,12> to
69          * have finer granularity. Without doing this, emc_dip_slope is zero all
70          * the time. Need to scale down emc_offset and emc_dip_offset
71          * from Hz to MHz to avoid integer overflow due to
72          * increased emc_slope and emc_dip_slope values.
73          */
74         unsigned long                   max_rate_3d;
75         unsigned long                   min_rate_3d;
76         long                            emc_slope;
77         long                            emc_offset;
78         long                            emc_dip_slope;
79         long                            emc_dip_offset;
80         long                            emc_xmid;
81
82         struct platform_device          *dev;
83         struct clk                      *clk_3d;
84         struct clk                      *clk_3d2;
85         struct clk                      *clk_3d_emc;
86
87         struct devfreq_dev_status       *dev_stat;
88
89         ktime_t                         last_request_time;
90
91         int                             last_event_type;
92 };
93
94 /*******************************************************************************
95  * Static variables for holding the device specific data
96  ******************************************************************************/
97
98 static struct power_profile_gr3d power_profile;
99
100 /* Convert struct clk to clk index */
101 static inline int clk_to_idx(struct clk *clk)
102 {
103         struct nvhost_device_data *pdata =
104                 platform_get_drvdata(power_profile.dev);
105         int i;
106
107         for (i = 0; i < NVHOST_MODULE_MAX_CLOCKS; i++) {
108                 if (clk == pdata->clk[i])
109                         break;
110         }
111
112         if (i == NVHOST_MODULE_MAX_CLOCKS)
113                 pr_err("scale3d: there is no such clk!\n");
114
115         return i;
116 }
117
118 /*******************************************************************************
119  * nvhost_scale3d_notify(dev, busy)
120  *
121  * Calling this function informs that gr3d is idling (..or busy). This data is
122  * used to estimate the current load
123  ******************************************************************************/
124
125 static void nvhost_scale3d_notify(struct platform_device *dev, int busy)
126 {
127         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
128         struct devfreq *df = pdata->power_manager;
129
130         /* If defreq is disabled, do nothing */
131         if (!df) {
132
133                 /* Ok.. make sure the 3d gets highest frequency always */
134                 if (busy) {
135                         unsigned long freq = power_profile.max_rate_3d;
136                         nvhost_scale3d_target(&dev->dev, &freq, 0);
137                 }
138
139                 return;
140         }
141
142         mutex_lock(&df->lock);
143         power_profile.last_event_type = busy ? DEVICE_BUSY : DEVICE_IDLE;
144         update_devfreq(df);
145         mutex_unlock(&df->lock);
146 }
147
148 void nvhost_scale3d_actmon_notify_idle(struct platform_device *dev)
149 {
150         nvhost_scale3d_notify(dev, 0);
151 }
152
153 void nvhost_scale3d_actmon_notify_busy(struct platform_device *dev)
154 {
155         nvhost_scale3d_notify(dev, 1);
156 }
157
158 /*******************************************************************************
159  * nvhost_scale3d_target(dev, *freq, flags)
160  *
161  * This function scales the clock
162  ******************************************************************************/
163
164 static int nvhost_scale3d_target(struct device *d, unsigned long *freq,
165                                 u32 flags)
166 {
167         long hz;
168         long after;
169
170         /* Inform that the clock is disabled */
171         if (!tegra_is_clk_enabled(power_profile.clk_3d)) {
172                 *freq = 0;
173                 return 0;
174         }
175
176         /* Limit the frequency */
177         if (*freq < power_profile.min_rate_3d)
178                 *freq = power_profile.min_rate_3d;
179         else if (*freq > power_profile.max_rate_3d)
180                 *freq = power_profile.max_rate_3d;
181
182         /* Check if we're already running at the desired speed */
183         if (*freq == clk_get_rate(power_profile.clk_3d))
184                 return 0;
185
186         /* Set GPU clockrate */
187         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
188                 nvhost_module_set_devfreq_rate(power_profile.dev,
189                                         clk_to_idx(power_profile.clk_3d2), 0);
190         nvhost_module_set_devfreq_rate(power_profile.dev,
191                                 clk_to_idx(power_profile.clk_3d), *freq);
192
193         /* Set EMC clockrate */
194         after = (long) clk_get_rate(power_profile.clk_3d);
195         after = INT_TO_FX(HZ_TO_MHZ(after));
196         hz = FXMUL(after, power_profile.emc_slope) +
197                 power_profile.emc_offset;
198
199         hz -= FXMUL(power_profile.emc_dip_slope,
200                 FXMUL(after - power_profile.emc_xmid,
201                         after - power_profile.emc_xmid)) +
202                 power_profile.emc_dip_offset;
203
204         hz = MHZ_TO_HZ(FX_TO_INT(hz + FX_HALF)); /* round to nearest */
205         hz = (hz < 0) ? 0 : hz;
206
207         nvhost_module_set_devfreq_rate(power_profile.dev,
208                         clk_to_idx(power_profile.clk_3d_emc), hz);
209
210         /* Get the new clockrate */
211         *freq = clk_get_rate(power_profile.clk_3d);
212
213         return 0;
214 }
215
216 /*******************************************************************************
217  * nvhost_scale3d_get_dev_status(dev, *stat)
218  *
219  * This function queries the current device status. *stat will have its private
220  * field set to an instance of nvhost_devfreq_ext_stat.
221  ******************************************************************************/
222
223 static int nvhost_scale3d_get_dev_status(struct device *d,
224                       struct devfreq_dev_status *stat)
225 {
226         struct platform_device *dev = to_platform_device(d);
227         struct nvhost_master *host_master = nvhost_get_host(dev);
228         struct nvhost_devfreq_ext_stat *ext_stat =
229                 power_profile.dev_stat->private_data;
230         u32 avg = 0;
231         ktime_t t;
232
233         /* Make sure there are correct values for the current frequency */
234         power_profile.dev_stat->current_frequency =
235                 clk_get_rate(power_profile.clk_3d);
236
237         /* Copy the contents of the current device status */
238         ext_stat->busy = power_profile.last_event_type;
239         *stat = *power_profile.dev_stat;
240
241         /* Read and scale AVG. AVG is scaled to interval 0-dt, where dt
242          * is the last time it was read. (this is really clumsy, but the
243          * governor uses internally time differences) */
244         actmon_op().read_avg_norm(host_master, &avg);
245         t = ktime_get();
246         stat->total_time = ktime_us_delta(t, power_profile.last_request_time);
247         stat->busy_time = (avg * stat->total_time) / 1000;
248         power_profile.last_request_time = t;
249
250         /* Finally, clear out the local values */
251         power_profile.dev_stat->total_time = 0;
252         power_profile.dev_stat->busy_time = 0;
253         power_profile.last_event_type = DEVICE_UNKNOWN;
254
255         tegra_edp_notify_gpu_load(avg);
256
257         return 0;
258 }
259
260 static struct devfreq_dev_profile nvhost_scale3d_devfreq_profile = {
261         .target         = nvhost_scale3d_target,
262         .get_dev_status = nvhost_scale3d_get_dev_status,
263 };
264
265 /*******************************************************************************
266  * nvhost_scale3d_calibrate_emc()
267  *
268  * Compute emc scaling parameters
269  *
270  * Remc = S * R3d + O - (Sd * (R3d - Rm)^2 + Od)
271  *
272  * Remc - 3d.emc rate
273  * R3d  - 3d.cbus rate
274  * Rm   - 3d.cbus 'middle' rate = (max + min)/2
275  * S    - emc_slope
276  * O    - emc_offset
277  * Sd   - emc_dip_slope
278  * Od   - emc_dip_offset
279  *
280  * this superposes a quadratic dip centered around the middle 3d
281  * frequency over a linear correlation of 3d.emc to 3d clock
282  * rates.
283  *
284  * S, O are chosen so that the maximum 3d rate produces the
285  * maximum 3d.emc rate exactly, and the minimum 3d rate produces
286  * at least the minimum 3d.emc rate.
287  *
288  * Sd and Od are chosen to produce the largest dip that will
289  * keep 3d.emc frequencies monotonously decreasing with 3d
290  * frequencies. To achieve this, the first derivative of Remc
291  * with respect to R3d should be zero for the minimal 3d rate:
292  *
293  *   R'emc = S - 2 * Sd * (R3d - Rm)
294  *   R'emc(R3d-min) = 0
295  *   S = 2 * Sd * (R3d-min - Rm)
296  *     = 2 * Sd * (R3d-min - R3d-max) / 2
297  *   Sd = S / (R3d-min - R3d-max)
298  *
299  *   +---------------------------------------------------+
300  *   | Sd = -(emc-max - emc-min) / (R3d-min - R3d-max)^2 |
301  *   +---------------------------------------------------+
302  *
303  *   dip = Sd * (R3d - Rm)^2 + Od
304  *
305  * requiring dip(R3d-min) = 0 and dip(R3d-max) = 0 gives
306  *
307  *   Sd * (R3d-min - Rm)^2 + Od = 0
308  *   Od = -Sd * ((R3d-min - R3d-max) / 2)^2
309  *      = -Sd * ((R3d-min - R3d-max)^2) / 4
310  *
311  *   +------------------------------+
312  *   | Od = (emc-max - emc-min) / 4 |
313  *   +------------------------------+
314  *
315  ******************************************************************************/
316
317 static void nvhost_scale3d_calibrate_emc(void)
318 {
319         long correction;
320         unsigned long max_emc;
321         unsigned long min_emc;
322         unsigned long min_rate_3d;
323         unsigned long max_rate_3d;
324
325         max_emc = clk_round_rate(power_profile.clk_3d_emc, UINT_MAX);
326         max_emc = INT_TO_FX(HZ_TO_MHZ(max_emc));
327
328         min_emc = clk_round_rate(power_profile.clk_3d_emc, 0);
329         min_emc = INT_TO_FX(HZ_TO_MHZ(min_emc));
330
331         max_rate_3d = INT_TO_FX(HZ_TO_MHZ(power_profile.max_rate_3d));
332         min_rate_3d = INT_TO_FX(HZ_TO_MHZ(power_profile.min_rate_3d));
333
334         power_profile.emc_slope =
335                 FXDIV((max_emc - min_emc), (max_rate_3d - min_rate_3d));
336         power_profile.emc_offset = max_emc -
337                 FXMUL(power_profile.emc_slope, max_rate_3d);
338         /* Guarantee max 3d rate maps to max emc rate */
339         power_profile.emc_offset += max_emc -
340                 (FXMUL(power_profile.emc_slope, max_rate_3d) +
341                 power_profile.emc_offset);
342
343         power_profile.emc_dip_offset = (max_emc - min_emc) / 4;
344         power_profile.emc_dip_slope =
345                 -4 * FXDIV(power_profile.emc_dip_offset,
346                 (FXMUL(max_rate_3d - min_rate_3d,
347                         max_rate_3d - min_rate_3d)));
348         power_profile.emc_xmid = (max_rate_3d + min_rate_3d) / 2;
349         correction =
350                 power_profile.emc_dip_offset +
351                         FXMUL(power_profile.emc_dip_slope,
352                         FXMUL(max_rate_3d - power_profile.emc_xmid,
353                                 max_rate_3d - power_profile.emc_xmid));
354         power_profile.emc_dip_offset -= correction;
355 }
356
357 /*******************************************************************************
358  * nvhost_scale3d_init(dev)
359  *
360  * Initialise 3d clock scaling for the given device. This function installs
361  * pod_scaling governor to handle the clock scaling.
362  ******************************************************************************/
363
364 void nvhost_scale3d_actmon_init(struct platform_device *dev)
365 {
366         struct nvhost_devfreq_ext_stat *ext_stat;
367         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
368
369         if (power_profile.init)
370                 return;
371
372         /* Get clocks */
373         power_profile.dev = dev;
374         power_profile.clk_3d = pdata->clk[0];
375         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) {
376                 power_profile.clk_3d2 = pdata->clk[1];
377                 power_profile.clk_3d_emc = pdata->clk[2];
378         } else
379                 power_profile.clk_3d_emc = pdata->clk[1];
380
381         /* Get frequency settings */
382         power_profile.max_rate_3d =
383                 clk_round_rate(power_profile.clk_3d, UINT_MAX);
384         power_profile.min_rate_3d =
385                 clk_round_rate(power_profile.clk_3d, 0);
386
387         nvhost_scale3d_devfreq_profile.initial_freq = power_profile.max_rate_3d;
388
389         if (power_profile.max_rate_3d == power_profile.min_rate_3d) {
390                 pr_warn("scale3d: 3d max rate = min rate (%lu), disabling\n",
391                         power_profile.max_rate_3d);
392                 goto err_bad_power_profile;
393         }
394
395         /* Reserve space for devfreq structures (dev_stat and ext_dev_stat) */
396         power_profile.dev_stat =
397                 kzalloc(sizeof(struct power_profile_gr3d), GFP_KERNEL);
398         if (!power_profile.dev_stat)
399                 goto err_devfreq_alloc;
400         ext_stat = kzalloc(sizeof(struct nvhost_devfreq_ext_stat), GFP_KERNEL);
401         if (!ext_stat)
402                 goto err_devfreq_ext_stat_alloc;
403
404         /* Initialise the dev_stat and ext_stat structures */
405         power_profile.dev_stat->private_data = ext_stat;
406         power_profile.last_event_type = DEVICE_UNKNOWN;
407         ext_stat->min_freq = power_profile.min_rate_3d;
408         ext_stat->max_freq = power_profile.max_rate_3d;
409
410         power_profile.last_request_time = ktime_get();
411
412         nvhost_scale3d_calibrate_emc();
413
414         /* Initialize actmon */
415         actmon_op().debug_init(nvhost_get_host(dev), pdata->debugfs);
416
417         /* Start using devfreq */
418         pdata->power_manager = devfreq_add_device(&dev->dev,
419                                 &nvhost_scale3d_devfreq_profile,
420                                 &nvhost_podgov,
421                                 NULL);
422
423         power_profile.init = 1;
424         return;
425
426 err_devfreq_ext_stat_alloc:
427         kfree(power_profile.dev_stat);
428 err_devfreq_alloc:
429 err_bad_power_profile:
430
431         return;
432
433 }
434
435 /*******************************************************************************
436  * nvhost_scale3d_deinit(dev)
437  *
438  * Stop 3d scaling for the given device.
439  ******************************************************************************/
440
441 void nvhost_scale3d_actmon_deinit(struct platform_device *dev)
442 {
443         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
444
445         if (!power_profile.init)
446                 return;
447
448         if (pdata->power_manager)
449                 devfreq_remove_device(pdata->power_manager);
450
451         kfree(power_profile.dev_stat->private_data);
452         kfree(power_profile.dev_stat);
453
454         power_profile.init = 0;
455 }
456