video: tegra: host: gk20a: Don't duplicate freqs
[linux-3.10.git] / drivers / video / tegra / host / gk20a / gk20a_scale.c
1 /*
2  * gk20a clock scaling profile
3  *
4  * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/devfreq.h>
20 #include <linux/debugfs.h>
21 #include <linux/types.h>
22 #include <linux/clk.h>
23 #include <linux/export.h>
24 #include <linux/slab.h>
25 #include <linux/clk/tegra.h>
26 #include <linux/tegra-soc.h>
27
28 #include <governor.h>
29
30 #include "dev.h"
31 #include "chip_support.h"
32 #include "nvhost_acm.h"
33 #include "gk20a.h"
34 #include "pmu_gk20a.h"
35 #include "clk_gk20a.h"
36 #include "nvhost_scale.h"
37 #include "gk20a_scale.h"
38
39 static ssize_t nvhost_gk20a_scale_load_show(struct device *dev,
40                                             struct device_attribute *attr,
41                                             char *buf)
42 {
43         struct platform_device *pdev = to_platform_device(dev);
44         struct gk20a *g = get_gk20a(pdev);
45         u32 busy_time;
46         ssize_t res;
47
48         nvhost_module_busy(g->dev);
49         gk20a_pmu_load_norm(g, &busy_time);
50         nvhost_module_idle(g->dev);
51
52         res = snprintf(buf, PAGE_SIZE, "%u\n", busy_time);
53
54         return res;
55 }
56
57 static DEVICE_ATTR(load, S_IRUGO, nvhost_gk20a_scale_load_show, NULL);
58
59 /*
60  * nvhost_scale_make_freq_table(profile)
61  *
62  * This function initialises the frequency table for the given device profile
63  */
64
65 static int nvhost_scale_make_freq_table(struct nvhost_device_profile *profile)
66 {
67         struct gk20a *g = get_gk20a(profile->pdev);
68         unsigned long *freqs;
69         int num_freqs, err;
70
71         /* make sure the clock is available */
72         if (!gk20a_clk_get(g))
73                 return -ENOSYS;
74
75         /* get gpu dvfs table */
76         err = tegra_dvfs_get_freqs(clk_get_parent(g->clk.tegra_clk),
77                                    &freqs, &num_freqs);
78         if (err)
79                 return -ENOSYS;
80
81         profile->devfreq_profile.freq_table = (unsigned int *)freqs;
82         profile->devfreq_profile.max_state = num_freqs;
83
84         return 0;
85 }
86
87 /*
88  * gk20a_scale_target(dev, *freq, flags)
89  *
90  * This function scales the clock
91  */
92
93 static int gk20a_scale_target(struct device *dev, unsigned long *freq,
94                               u32 flags)
95 {
96         struct gk20a *g = get_gk20a(to_platform_device(dev));
97         struct nvhost_device_data *pdata = dev_get_drvdata(dev);
98         struct nvhost_device_profile *profile = pdata->power_profile;
99         unsigned long rounded_rate = gk20a_clk_round_rate(g, *freq);
100
101         if (gk20a_clk_get_rate(g) == rounded_rate) {
102                 *freq = rounded_rate;
103                 return 0;
104         }
105
106         gk20a_clk_set_rate(g, rounded_rate);
107         if (pdata->scaling_post_cb)
108                 pdata->scaling_post_cb(profile, rounded_rate);
109         *freq = gk20a_clk_get_rate(g);
110
111         return 0;
112 }
113
114 /*
115  * update_load_estimate_gpmu(profile)
116  *
117  * Update load estimate using gpmu. The gpmu value is normalised
118  * based on the time it was asked last time.
119  */
120
121 static void update_load_estimate_gpmu(struct platform_device *pdev)
122 {
123         struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
124         struct nvhost_device_profile *profile = pdata->power_profile;
125         struct gk20a *g = get_gk20a(pdev);
126         unsigned long dt;
127         u32 busy_time;
128         ktime_t t;
129
130         t = ktime_get();
131         dt = ktime_us_delta(t, profile->last_event_time);
132
133         profile->dev_stat.total_time = dt;
134         profile->last_event_time = t;
135         gk20a_pmu_load_norm(g, &busy_time);
136         profile->dev_stat.busy_time = (busy_time * dt) / 1000;
137 }
138
139 /*
140  * gk20a_scale_notify(pdev, busy)
141  *
142  * Calling this function informs that the device is idling (..or busy). This
143  * data is used to estimate the current load
144  */
145
146 static void gk20a_scale_notify(struct platform_device *pdev, bool busy)
147 {
148         struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
149         struct nvhost_device_profile *profile = pdata->power_profile;
150         struct devfreq *devfreq = pdata->power_manager;
151
152         /* Is the device profile initialised? */
153         if (!(profile && devfreq))
154                 return;
155
156         mutex_lock(&devfreq->lock);
157         profile->last_event_type = busy ? DEVICE_BUSY : DEVICE_IDLE;
158         update_devfreq(devfreq);
159         mutex_unlock(&devfreq->lock);
160 }
161
162 void nvhost_gk20a_scale_notify_idle(struct platform_device *pdev)
163 {
164         gk20a_scale_notify(pdev, false);
165
166 }
167
168 void nvhost_gk20a_scale_notify_busy(struct platform_device *pdev)
169 {
170         gk20a_scale_notify(pdev, true);
171 }
172
173 /*
174  * gk20a_scale_get_dev_status(dev, *stat)
175  *
176  * This function queries the current device status.
177  */
178
179 static int gk20a_scale_get_dev_status(struct device *dev,
180                                       struct devfreq_dev_status *stat)
181 {
182         struct nvhost_device_data *pdata = dev_get_drvdata(dev);
183         struct nvhost_device_profile *profile = pdata->power_profile;
184         struct gk20a *g = get_gk20a(to_platform_device(dev));
185
186         /* Make sure there are correct values for the current frequency */
187         profile->dev_stat.current_frequency = gk20a_clk_get_rate(g);
188
189         /* Update load estimate */
190         update_load_estimate_gpmu(to_platform_device(dev));
191
192         /* Copy the contents of the current device status */
193         *stat = profile->dev_stat;
194
195         /* Finally, clear out the local values */
196         profile->dev_stat.total_time = 0;
197         profile->dev_stat.busy_time = 0;
198         profile->last_event_type = DEVICE_UNKNOWN;
199
200         return 0;
201 }
202
203 /*
204  * gk20a_scale_init(pdev)
205  */
206
207 void nvhost_gk20a_scale_init(struct platform_device *pdev)
208 {
209         struct gk20a *g = get_gk20a(pdev);
210         struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
211         struct nvhost_device_profile *profile;
212
213         if (pdata->power_profile)
214                 return;
215
216         profile = kzalloc(sizeof(struct nvhost_device_profile), GFP_KERNEL);
217         if (!profile)
218                 return;
219         profile->pdev = pdev;
220         profile->last_event_type = DEVICE_UNKNOWN;
221
222         /* Initialize devfreq related structures */
223         profile->dev_stat.private_data = &profile->ext_stat;
224         profile->ext_stat.min_freq = gk20a_clk_round_rate(g, 0);
225         profile->ext_stat.max_freq = gk20a_clk_round_rate(g, UINT_MAX);
226         profile->ext_stat.busy = DEVICE_UNKNOWN;
227
228         if (profile->ext_stat.min_freq == profile->ext_stat.max_freq) {
229                 dev_warn(&pdev->dev, "max rate = min rate (%lu), disabling scaling\n",
230                          profile->ext_stat.min_freq);
231                 goto err_fetch_clocks;
232         }
233
234         if (device_create_file(&pdev->dev, &dev_attr_load))
235                 goto err_create_sysfs_entry;
236
237         /* Store device profile so we can access it if devfreq governor
238          * init needs that */
239         pdata->power_profile = profile;
240
241         if (pdata->devfreq_governor) {
242                 struct devfreq *devfreq;
243                 int err;
244
245                 profile->devfreq_profile.target = gk20a_scale_target;
246                 profile->devfreq_profile.get_dev_status =
247                         gk20a_scale_get_dev_status;
248                 err = nvhost_scale_make_freq_table(profile);
249                 if (err)
250                         goto err_get_freqs;
251
252                 devfreq = devfreq_add_device(&pdev->dev,
253                                         &profile->devfreq_profile,
254                                         pdata->devfreq_governor, NULL);
255
256                 if (IS_ERR(devfreq))
257                         devfreq = NULL;
258
259                 pdata->power_manager = devfreq;
260         }
261         return;
262
263 err_get_freqs:
264         device_remove_file(&pdev->dev, &dev_attr_load);
265 err_create_sysfs_entry:
266 err_fetch_clocks:
267         kfree(pdata->power_profile);
268         pdata->power_profile = NULL;
269 }
270
271 /*
272  * gk20a_scale_deinit(dev)
273  *
274  * Stop scaling for the given device.
275  */
276
277 void nvhost_gk20a_scale_deinit(struct platform_device *pdev)
278 {
279         struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
280         struct nvhost_device_profile *profile = pdata->power_profile;
281
282         if (!profile)
283                 return;
284
285         if (pdata->power_manager)
286                 devfreq_remove_device(pdata->power_manager);
287
288         device_remove_file(&pdev->dev, &dev_attr_load);
289
290         kfree(profile);
291         pdata->power_profile = NULL;
292 }
293
294 /*
295  * gk20a_scale_hw_init(dev)
296  *
297  * Initialize hardware portion of the device
298  */
299
300 void nvhost_gk20a_scale_hw_init(struct platform_device *pdev)
301 {
302         struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
303         struct nvhost_device_profile *profile = pdata->power_profile;
304
305         /* make sure that scaling has bee initialised */
306         if (!profile)
307                 return;
308
309         profile->dev_stat.total_time = 0;
310         profile->last_event_time = ktime_get();
311 }