summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
diff options
context:
space:
mode:
authorArto Merilainen <amerilainen@nvidia.com>2014-03-19 03:38:25 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:08:53 -0400
commita9785995d5f22aaeb659285f8aeb64d8b56982e0 (patch)
treecc75f75bcf43db316a002a7a240b81f299bf6d7f /drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
parent61efaf843c22b85424036ec98015121c08f5f16c (diff)
gpu: nvgpu: Add NVIDIA GPU Driver
This patch moves the NVIDIA GPU driver to a new location. Bug 1482562 Change-Id: I24293810b9d0f1504fd9be00135e21dad656ccb6 Signed-off-by: Arto Merilainen <amerilainen@nvidia.com> Reviewed-on: http://git-master/r/383722 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
new file mode 100644
index 00000000..f6b43f50
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
@@ -0,0 +1,335 @@
1/*
2 * drivers/video/tegra/host/gk20a/gk20a_sysfs.c
3 *
4 * GK20A Graphics
5 *
6 * Copyright (c) 2011-2014, 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#include <linux/platform_device.h>
22#include <linux/pm_runtime.h>
23#include <linux/kernel.h>
24#include <linux/fb.h>
25
26#include <mach/clk.h>
27
28#include "gk20a.h"
29#include "gr_gk20a.h"
30#include "fifo_gk20a.h"
31
32
33#define PTIMER_FP_FACTOR 1000000
34/* PTIMER_REF_FREQ_HZ corresponds to a period of 32 nanoseconds. 32 ns is
35 the resolution of ptimer. */
36#define PTIMER_REF_FREQ_HZ 31250000
37
38
39static ssize_t elcg_enable_store(struct device *device,
40 struct device_attribute *attr, const char *buf, size_t count)
41{
42 struct platform_device *ndev = to_platform_device(device);
43 struct gk20a *g = get_gk20a(ndev);
44 unsigned long val = 0;
45
46 if (kstrtoul(buf, 10, &val) < 0)
47 return -EINVAL;
48
49 gk20a_busy(g->dev);
50 if (val) {
51 g->elcg_enabled = true;
52 gr_gk20a_init_elcg_mode(g, ELCG_AUTO, ENGINE_GR_GK20A);
53 gr_gk20a_init_elcg_mode(g, ELCG_AUTO, ENGINE_CE2_GK20A);
54 } else {
55 g->elcg_enabled = false;
56 gr_gk20a_init_elcg_mode(g, ELCG_RUN, ENGINE_GR_GK20A);
57 gr_gk20a_init_elcg_mode(g, ELCG_RUN, ENGINE_CE2_GK20A);
58 }
59 gk20a_idle(g->dev);
60
61 dev_info(device, "ELCG is %s.\n", g->elcg_enabled ? "enabled" :
62 "disabled");
63
64 return count;
65}
66
67static ssize_t elcg_enable_read(struct device *device,
68 struct device_attribute *attr, char *buf)
69{
70 struct platform_device *ndev = to_platform_device(device);
71 struct gk20a *g = get_gk20a(ndev);
72
73 return sprintf(buf, "%d\n", g->elcg_enabled ? 1 : 0);
74}
75
76static DEVICE_ATTR(elcg_enable, S_IRWXUGO, elcg_enable_read, elcg_enable_store);
77
78static ssize_t blcg_enable_store(struct device *device,
79 struct device_attribute *attr, const char *buf, size_t count)
80{
81 struct platform_device *ndev = to_platform_device(device);
82 struct gk20a *g = get_gk20a(ndev);
83 unsigned long val = 0;
84
85 if (kstrtoul(buf, 10, &val) < 0)
86 return -EINVAL;
87
88 if (val)
89 g->blcg_enabled = true;
90 else
91 g->blcg_enabled = false;
92
93 gk20a_busy(g->dev);
94 g->ops.clock_gating.blcg_gr_load_gating_prod(g, g->blcg_enabled);
95 gk20a_idle(g->dev);
96
97 dev_info(device, "BLCG is %s.\n", g->blcg_enabled ? "enabled" :
98 "disabled");
99
100 return count;
101}
102
103static ssize_t blcg_enable_read(struct device *device,
104 struct device_attribute *attr, char *buf)
105{
106 struct platform_device *ndev = to_platform_device(device);
107 struct gk20a *g = get_gk20a(ndev);
108
109 return sprintf(buf, "%d\n", g->blcg_enabled ? 1 : 0);
110}
111
112static DEVICE_ATTR(blcg_enable, S_IRWXUGO, blcg_enable_read, blcg_enable_store);
113
114static ssize_t slcg_enable_store(struct device *device,
115 struct device_attribute *attr, const char *buf, size_t count)
116{
117 struct platform_device *ndev = to_platform_device(device);
118 struct gk20a *g = get_gk20a(ndev);
119 unsigned long val = 0;
120
121 if (kstrtoul(buf, 10, &val) < 0)
122 return -EINVAL;
123
124 if (val)
125 g->slcg_enabled = true;
126 else
127 g->slcg_enabled = false;
128
129 /*
130 * TODO: slcg_therm_load_gating is not enabled anywhere during
131 * init. Therefore, it would be incongruous to add it here. Once
132 * it is added to init, we should add it here too.
133 */
134 gk20a_busy(g->dev);
135 g->ops.clock_gating.slcg_gr_load_gating_prod(g, g->slcg_enabled);
136 g->ops.clock_gating.slcg_perf_load_gating_prod(g, g->slcg_enabled);
137 gk20a_idle(g->dev);
138
139 dev_info(device, "SLCG is %s.\n", g->slcg_enabled ? "enabled" :
140 "disabled");
141
142 return count;
143}
144
145static ssize_t slcg_enable_read(struct device *device,
146 struct device_attribute *attr, char *buf)
147{
148 struct platform_device *ndev = to_platform_device(device);
149 struct gk20a *g = get_gk20a(ndev);
150
151 return sprintf(buf, "%d\n", g->slcg_enabled ? 1 : 0);
152}
153
154static DEVICE_ATTR(slcg_enable, S_IRWXUGO, slcg_enable_read, slcg_enable_store);
155
156static ssize_t ptimer_scale_factor_show(struct device *dev,
157 struct device_attribute *attr,
158 char *buf)
159{
160 u32 tsc_freq_hz = clk_get_rate(clk_get_sys(NULL, "clk_m"));
161 u32 scaling_factor_fp = (u32)(PTIMER_REF_FREQ_HZ) /
162 ((u32)(tsc_freq_hz) /
163 (u32)(PTIMER_FP_FACTOR));
164 ssize_t res = snprintf(buf,
165 PAGE_SIZE,
166 "%u.%u\n",
167 scaling_factor_fp / PTIMER_FP_FACTOR,
168 scaling_factor_fp % PTIMER_FP_FACTOR);
169
170 return res;
171}
172
173static DEVICE_ATTR(ptimer_scale_factor,
174 S_IRUGO,
175 ptimer_scale_factor_show,
176 NULL);
177
178static ssize_t railgate_delay_store(struct device *dev,
179 struct device_attribute *attr,
180 const char *buf, size_t count)
181{
182 struct gk20a_platform *platform = dev_get_drvdata(dev);
183 int railgate_delay = 0, ret = 0;
184
185 if (!platform->can_railgate) {
186 dev_info(dev, "does not support power-gating\n");
187 return count;
188 }
189
190 ret = sscanf(buf, "%d", &railgate_delay);
191 if (ret == 1 && railgate_delay >= 0) {
192 struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
193 platform->railgate_delay = railgate_delay;
194 pm_genpd_set_poweroff_delay(genpd, platform->railgate_delay);
195 } else
196 dev_err(dev, "Invalid powergate delay\n");
197
198 return count;
199}
200static ssize_t railgate_delay_show(struct device *dev,
201 struct device_attribute *attr, char *buf)
202{
203 struct gk20a_platform *platform = dev_get_drvdata(dev);
204 return snprintf(buf, PAGE_SIZE, "%d\n", platform->railgate_delay);
205}
206static DEVICE_ATTR(railgate_delay, S_IRWXUGO, railgate_delay_show,
207 railgate_delay_store);
208
209static ssize_t clockgate_delay_store(struct device *dev,
210 struct device_attribute *attr,
211 const char *buf, size_t count)
212{
213 struct gk20a_platform *platform = dev_get_drvdata(dev);
214 int clockgate_delay = 0, ret = 0;
215
216 ret = sscanf(buf, "%d", &clockgate_delay);
217 if (ret == 1 && clockgate_delay >= 0) {
218 platform->clockgate_delay = clockgate_delay;
219 pm_runtime_set_autosuspend_delay(dev,
220 platform->clockgate_delay);
221 } else
222 dev_err(dev, "Invalid clockgate delay\n");
223
224 return count;
225}
226static ssize_t clockgate_delay_show(struct device *dev,
227 struct device_attribute *attr, char *buf)
228{
229 struct gk20a_platform *platform = dev_get_drvdata(dev);
230 return snprintf(buf, PAGE_SIZE, "%d\n", platform->clockgate_delay);
231}
232static DEVICE_ATTR(clockgate_delay, S_IRWXUGO, clockgate_delay_show,
233 clockgate_delay_store);
234
235static ssize_t counters_show(struct device *dev,
236 struct device_attribute *attr, char *buf)
237{
238 struct platform_device *pdev = to_platform_device(dev);
239 struct gk20a *g = get_gk20a(pdev);
240 u32 busy_cycles, total_cycles;
241 ssize_t res;
242
243 gk20a_pmu_get_load_counters(g, &busy_cycles, &total_cycles);
244
245 res = snprintf(buf, PAGE_SIZE, "%u %u\n", busy_cycles, total_cycles);
246
247 return res;
248}
249
250static DEVICE_ATTR(counters, S_IRUGO, counters_show, NULL);
251static ssize_t counters_show_reset(struct device *dev,
252 struct device_attribute *attr, char *buf)
253{
254 ssize_t res = counters_show(dev, attr, buf);
255 struct platform_device *pdev = to_platform_device(dev);
256 struct gk20a *g = get_gk20a(pdev);
257
258 gk20a_pmu_reset_load_counters(g);
259
260 return res;
261}
262
263static DEVICE_ATTR(counters_reset, S_IRUGO, counters_show_reset, NULL);
264
265static ssize_t elpg_enable_store(struct device *device,
266 struct device_attribute *attr, const char *buf, size_t count)
267{
268 struct platform_device *ndev = to_platform_device(device);
269 struct gk20a *g = get_gk20a(ndev);
270 unsigned long val = 0;
271
272 if (kstrtoul(buf, 10, &val) < 0)
273 return -EINVAL;
274
275 /*
276 * Since elpg is refcounted, we should not unnecessarily call
277 * enable/disable if it is already so.
278 */
279 gk20a_channel_busy(g->dev);
280 if (val && !g->elpg_enabled) {
281 g->elpg_enabled = true;
282 gk20a_pmu_enable_elpg(g);
283 } else if (!val && g->elpg_enabled) {
284 g->elpg_enabled = false;
285 gk20a_pmu_disable_elpg(g);
286 }
287 gk20a_channel_idle(g->dev);
288
289 dev_info(device, "ELPG is %s.\n", g->elpg_enabled ? "enabled" :
290 "disabled");
291
292 return count;
293}
294
295static ssize_t elpg_enable_read(struct device *device,
296 struct device_attribute *attr, char *buf)
297{
298 struct platform_device *ndev = to_platform_device(device);
299 struct gk20a *g = get_gk20a(ndev);
300
301 return sprintf(buf, "%d\n", g->elpg_enabled ? 1 : 0);
302}
303
304static DEVICE_ATTR(elpg_enable, S_IRWXUGO, elpg_enable_read, elpg_enable_store);
305
306void gk20a_remove_sysfs(struct device *dev)
307{
308 device_remove_file(dev, &dev_attr_elcg_enable);
309 device_remove_file(dev, &dev_attr_blcg_enable);
310 device_remove_file(dev, &dev_attr_slcg_enable);
311 device_remove_file(dev, &dev_attr_ptimer_scale_factor);
312 device_remove_file(dev, &dev_attr_elpg_enable);
313 device_remove_file(dev, &dev_attr_counters);
314 device_remove_file(dev, &dev_attr_counters_reset);
315 device_remove_file(dev, &dev_attr_railgate_delay);
316 device_remove_file(dev, &dev_attr_clockgate_delay);
317}
318
319void gk20a_create_sysfs(struct platform_device *dev)
320{
321 int error = 0;
322
323 error |= device_create_file(&dev->dev, &dev_attr_elcg_enable);
324 error |= device_create_file(&dev->dev, &dev_attr_blcg_enable);
325 error |= device_create_file(&dev->dev, &dev_attr_slcg_enable);
326 error |= device_create_file(&dev->dev, &dev_attr_ptimer_scale_factor);
327 error |= device_create_file(&dev->dev, &dev_attr_elpg_enable);
328 error |= device_create_file(&dev->dev, &dev_attr_counters);
329 error |= device_create_file(&dev->dev, &dev_attr_counters_reset);
330 error |= device_create_file(&dev->dev, &dev_attr_railgate_delay);
331 error |= device_create_file(&dev->dev, &dev_attr_clockgate_delay);
332
333 if (error)
334 dev_err(&dev->dev, "Failed to create sysfs attributes!\n");
335}