summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2017-06-19 17:17:03 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-06-20 22:14:15 -0400
commitd0ea8fe969b2a8f7509621103c1ead83187b798b (patch)
treeb95eb51dffcdfff4510e7980a031721a057931f7 /drivers/gpu/nvgpu/common
parent7437fefa9016ab8904c79f521276f5c41e40c449 (diff)
gpu: nvgpu: Merge tegra/linux to common/linux
tegra/linux path was created to separate Tegra kernel specific dependencies from common Linux specific dependencies. The split has not really worked, so merge tegra/linux to common/linux. JIRA NVGPU-38 Change-Id: I582e12a0a8b5de62a29e41a37f4f8b8caae955fc Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1505178 Reviewed-by: Alex Waterman <alexw@nvidia.com> GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/common')
-rw-r--r--drivers/gpu/nvgpu/common/linux/clk.c133
-rw-r--r--drivers/gpu/nvgpu/common/linux/clk.h22
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.c1111
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.h25
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c786
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h46
6 files changed, 2123 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/clk.c b/drivers/gpu/nvgpu/common/linux/clk.c
new file mode 100644
index 00000000..775e5661
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/clk.c
@@ -0,0 +1,133 @@
1/*
2 * Linux clock support
3 *
4 * Copyright (c) 2017, 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/clk.h>
20#include <linux/version.h>
21
22#include <soc/tegra/tegra-dvfs.h>
23
24#include "clk.h"
25#include "gk20a/gk20a.h"
26#include "gk20a/platform_gk20a.h"
27
28static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain)
29{
30 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
31 unsigned long ret;
32
33 switch (api_domain) {
34 case CTRL_CLK_DOMAIN_GPCCLK:
35 if (g->clk.tegra_clk)
36 ret = clk_get_rate(g->clk.tegra_clk);
37 else
38 ret = clk_get_rate(platform->clk[0]);
39 break;
40 case CTRL_CLK_DOMAIN_PWRCLK:
41 ret = clk_get_rate(platform->clk[1]);
42 break;
43 default:
44 nvgpu_err(g, "unknown clock: %u", api_domain);
45 ret = 0;
46 break;
47 }
48
49 return ret;
50}
51
52static int nvgpu_linux_clk_set_rate(struct gk20a *g,
53 u32 api_domain, unsigned long rate)
54{
55 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
56 int ret;
57
58 switch (api_domain) {
59 case CTRL_CLK_DOMAIN_GPCCLK:
60 if (g->clk.tegra_clk)
61 ret = clk_set_rate(g->clk.tegra_clk, rate);
62 else
63 ret = clk_set_rate(platform->clk[0], rate);
64 break;
65 case CTRL_CLK_DOMAIN_PWRCLK:
66 ret = clk_set_rate(platform->clk[1], rate);
67 break;
68 default:
69 nvgpu_err(g, "unknown clock: %u", api_domain);
70 ret = -EINVAL;
71 break;
72 }
73
74 return ret;
75}
76
77static unsigned long nvgpu_linux_get_fmax_at_vmin_safe(struct clk_gk20a *clk)
78{
79 /*
80 * On Tegra GPU clock exposed to frequency governor is a shared user on
81 * GPCPLL bus (gbus). The latter can be accessed as GPU clock parent.
82 * Respectively the grandparent is PLL reference clock.
83 */
84 return tegra_dvfs_get_fmax_at_vmin_safe_t(
85 clk_get_parent(clk->tegra_clk));
86}
87
88static u32 nvgpu_linux_get_ref_clock_rate(struct gk20a *g)
89{
90 struct clk *c;
91
92 c = clk_get_sys("gpu_ref", "gpu_ref");
93 if (IS_ERR(c)) {
94 nvgpu_err(g, "failed to get GPCPLL reference clock");
95 return 0;
96 }
97
98 return clk_get_rate(c);
99}
100
101static int nvgpu_linux_predict_mv_at_hz_cur_tfloor(struct clk_gk20a *clk,
102 unsigned long rate)
103{
104 return tegra_dvfs_predict_mv_at_hz_cur_tfloor(
105 clk_get_parent(clk->tegra_clk), rate);
106}
107
108static unsigned long nvgpu_linux_get_maxrate(struct clk_gk20a *clk)
109{
110 return tegra_dvfs_get_maxrate(clk_get_parent(clk->tegra_clk));
111}
112
113static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk)
114{
115 return clk_prepare_enable(clk->tegra_clk);
116}
117
118static void nvgpu_linux_disable_unprepare(struct clk_gk20a *clk)
119{
120 clk_disable_unprepare(clk->tegra_clk);
121}
122
123void nvgpu_linux_init_clk_support(struct gk20a *g)
124{
125 g->ops.clk.get_rate = nvgpu_linux_clk_get_rate;
126 g->ops.clk.set_rate = nvgpu_linux_clk_set_rate;
127 g->ops.clk.get_fmax_at_vmin_safe = nvgpu_linux_get_fmax_at_vmin_safe;
128 g->ops.clk.get_ref_clock_rate = nvgpu_linux_get_ref_clock_rate;
129 g->ops.clk.predict_mv_at_hz_cur_tfloor = nvgpu_linux_predict_mv_at_hz_cur_tfloor;
130 g->ops.clk.get_maxrate = nvgpu_linux_get_maxrate;
131 g->ops.clk.prepare_enable = nvgpu_linux_prepare_enable;
132 g->ops.clk.disable_unprepare = nvgpu_linux_disable_unprepare;
133}
diff --git a/drivers/gpu/nvgpu/common/linux/clk.h b/drivers/gpu/nvgpu/common/linux/clk.h
new file mode 100644
index 00000000..614a7fd7
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/clk.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef NVGPU_COMMON_LINUX_CLK_H
18
19struct gk20a;
20void nvgpu_linux_init_clk_support(struct gk20a *g);
21
22#endif
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.c
new file mode 100644
index 00000000..b0f6ee7d
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.c
@@ -0,0 +1,1111 @@
1/*
2 * GK20A Tegra Platform Interface
3 *
4 * Copyright (c) 2014-2017, 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
16#include <linux/version.h>
17#include <linux/of_platform.h>
18#include <linux/debugfs.h>
19#include <linux/platform_data/tegra_edp.h>
20#include <linux/delay.h>
21#include <uapi/linux/nvgpu.h>
22#include <linux/dma-buf.h>
23#include <linux/dma-attrs.h>
24#include <linux/nvmap.h>
25#include <linux/reset.h>
26#if defined(CONFIG_TEGRA_DVFS)
27#include <linux/tegra_soctherm.h>
28#endif
29#include <linux/platform/tegra/common.h>
30#include <linux/platform/tegra/mc.h>
31#include <linux/clk/tegra.h>
32#if defined(CONFIG_COMMON_CLK)
33#include <soc/tegra/tegra-dvfs.h>
34#endif
35#ifdef CONFIG_TEGRA_BWMGR
36#include <linux/platform/tegra/emc_bwmgr.h>
37#endif
38
39#include <linux/platform/tegra/tegra_emc.h>
40#include <soc/tegra/chip-id.h>
41
42#include <nvgpu/kmem.h>
43#include <nvgpu/bug.h>
44#include <nvgpu/enabled.h>
45#include <nvgpu/nvhost.h>
46
47#include <nvgpu/linux/dma.h>
48
49#include "gk20a/gk20a.h"
50#include "gk20a/hal_gk20a.h"
51#include "gk20a/platform_gk20a.h"
52#include "gk20a/gk20a_scale.h"
53#include "gm20b/clk_gm20b.h"
54
55#include "clk.h"
56
57#define TEGRA_GK20A_BW_PER_FREQ 32
58#define TEGRA_GM20B_BW_PER_FREQ 64
59#define TEGRA_DDR3_BW_PER_FREQ 16
60#define TEGRA_DDR4_BW_PER_FREQ 16
61#define MC_CLIENT_GPU 34
62#define PMC_GPU_RG_CNTRL_0 0x2d4
63
64#ifdef CONFIG_COMMON_CLK
65#define GPU_RAIL_NAME "vdd-gpu"
66#else
67#define GPU_RAIL_NAME "vdd_gpu"
68#endif
69
70extern struct device tegra_vpr_dev;
71
72#ifdef CONFIG_TEGRA_BWMGR
73struct gk20a_emc_params {
74 unsigned long bw_ratio;
75 unsigned long freq_last_set;
76 struct tegra_bwmgr_client *bwmgr_cl;
77};
78#else
79struct gk20a_emc_params {
80 unsigned long bw_ratio;
81 unsigned long freq_last_set;
82};
83#endif
84
85static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
86static inline u32 __maybe_unused pmc_read(unsigned long reg)
87{
88 return readl(pmc + reg);
89}
90
91static inline void __maybe_unused pmc_write(u32 val, unsigned long reg)
92{
93 writel_relaxed(val, pmc + reg);
94}
95#define MHZ_TO_HZ(x) ((x) * 1000000)
96#define HZ_TO_MHZ(x) ((x) / 1000000)
97
98static void gk20a_tegra_secure_page_destroy(struct gk20a *g,
99 struct secure_page_buffer *secure_buffer)
100{
101 DEFINE_DMA_ATTRS(attrs);
102 dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, __DMA_ATTR(attrs));
103 dma_free_attrs(&tegra_vpr_dev, secure_buffer->size,
104 (void *)(uintptr_t)secure_buffer->iova,
105 secure_buffer->iova, __DMA_ATTR(attrs));
106
107 secure_buffer->destroy = NULL;
108}
109
110int gk20a_tegra_secure_page_alloc(struct device *dev)
111{
112 struct gk20a_platform *platform = dev_get_drvdata(dev);
113 struct gk20a *g = get_gk20a(dev);
114 struct secure_page_buffer *secure_buffer = &platform->secure_buffer;
115 DEFINE_DMA_ATTRS(attrs);
116 dma_addr_t iova;
117 size_t size = PAGE_SIZE;
118
119 if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
120 return -EINVAL;
121
122 dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, __DMA_ATTR(attrs));
123 (void)dma_alloc_attrs(&tegra_vpr_dev, size, &iova,
124 GFP_KERNEL, __DMA_ATTR(attrs));
125 if (dma_mapping_error(&tegra_vpr_dev, iova))
126 return -ENOMEM;
127
128 secure_buffer->size = size;
129 secure_buffer->iova = iova;
130 secure_buffer->destroy = gk20a_tegra_secure_page_destroy;
131
132 return 0;
133}
134
135static void gk20a_tegra_secure_destroy(struct gk20a *g,
136 struct gr_ctx_buffer_desc *desc)
137{
138 DEFINE_DMA_ATTRS(attrs);
139
140 if (desc->mem.priv.sgt) {
141 phys_addr_t pa = sg_phys(desc->mem.priv.sgt->sgl);
142 dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, __DMA_ATTR(attrs));
143 dma_free_attrs(&tegra_vpr_dev, desc->mem.size,
144 (void *)(uintptr_t)pa,
145 pa, __DMA_ATTR(attrs));
146 nvgpu_free_sgtable(g, &desc->mem.priv.sgt);
147 desc->mem.priv.sgt = NULL;
148 }
149}
150
151static int gk20a_tegra_secure_alloc(struct gk20a *g,
152 struct gr_ctx_buffer_desc *desc,
153 size_t size)
154{
155 struct device *dev = dev_from_gk20a(g);
156 struct gk20a_platform *platform = dev_get_drvdata(dev);
157 DEFINE_DMA_ATTRS(attrs);
158 dma_addr_t iova;
159 struct sg_table *sgt;
160 struct page *page;
161 int err = 0;
162
163 dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, __DMA_ATTR(attrs));
164 (void)dma_alloc_attrs(&tegra_vpr_dev, size, &iova,
165 GFP_KERNEL, __DMA_ATTR(attrs));
166 if (dma_mapping_error(&tegra_vpr_dev, iova))
167 return -ENOMEM;
168
169 sgt = nvgpu_kzalloc(platform->g, sizeof(*sgt));
170 if (!sgt) {
171 nvgpu_err(platform->g, "failed to allocate memory");
172 goto fail;
173 }
174 err = sg_alloc_table(sgt, 1, GFP_KERNEL);
175 if (err) {
176 nvgpu_err(platform->g, "failed to allocate sg_table");
177 goto fail_sgt;
178 }
179 page = phys_to_page(iova);
180 sg_set_page(sgt->sgl, page, size, 0);
181 /* This bypasses SMMU for VPR during gmmu_map. */
182 sg_dma_address(sgt->sgl) = 0;
183
184 desc->destroy = gk20a_tegra_secure_destroy;
185
186 desc->mem.priv.sgt = sgt;
187 desc->mem.size = size;
188 desc->mem.aperture = APERTURE_SYSMEM;
189
190 if (platform->secure_buffer.destroy)
191 platform->secure_buffer.destroy(g, &platform->secure_buffer);
192
193 return err;
194
195fail_sgt:
196 nvgpu_kfree(platform->g, sgt);
197fail:
198 dma_free_attrs(&tegra_vpr_dev, desc->mem.size,
199 (void *)(uintptr_t)iova, iova, __DMA_ATTR(attrs));
200 return err;
201}
202
203/*
204 * gk20a_tegra_get_emc_rate()
205 *
206 * This function returns the minimum emc clock based on gpu frequency
207 */
208
209static unsigned long gk20a_tegra_get_emc_rate(struct gk20a *g,
210 struct gk20a_emc_params *emc_params)
211{
212 unsigned long gpu_freq, gpu_fmax_at_vmin;
213 unsigned long emc_rate, emc_scale;
214
215 gpu_freq = clk_get_rate(g->clk.tegra_clk);
216 gpu_fmax_at_vmin = tegra_dvfs_get_fmax_at_vmin_safe_t(
217 clk_get_parent(g->clk.tegra_clk));
218
219 /* When scaling emc, account for the gpu load when the
220 * gpu frequency is less than or equal to fmax@vmin. */
221 if (gpu_freq <= gpu_fmax_at_vmin)
222 emc_scale = min(g->pmu.load_avg, g->emc3d_ratio);
223 else
224 emc_scale = g->emc3d_ratio;
225
226 emc_rate =
227 (HZ_TO_MHZ(gpu_freq) * emc_params->bw_ratio * emc_scale) / 1000;
228
229 return MHZ_TO_HZ(emc_rate);
230}
231
232/*
233 * gk20a_tegra_postscale(profile, freq)
234 *
235 * This function sets emc frequency based on current gpu frequency
236 */
237
238static void gk20a_tegra_postscale(struct device *dev,
239 unsigned long freq)
240{
241 struct gk20a_platform *platform = dev_get_drvdata(dev);
242 struct gk20a_scale_profile *profile = platform->g->scale_profile;
243 struct gk20a_emc_params *emc_params = profile->private_data;
244 struct gk20a *g = get_gk20a(dev);
245 struct clk *emc_clk = platform->clk[2];
246 enum tegra_chipid chip_id = tegra_get_chip_id();
247 unsigned long emc_target;
248 unsigned long emc_freq_lower, emc_freq_upper, emc_freq_rounded;
249
250 emc_target = gk20a_tegra_get_emc_rate(g, emc_params);
251
252 switch (chip_id) {
253 case TEGRA124:
254 case TEGRA132:
255 /* T124 and T132 don't apply any rounding. The resulting
256 * emc frequency gets implicitly rounded up after issuing
257 * the clock_set_request.
258 * So explicitly round up the emc target here to achieve
259 * the same outcome. */
260 emc_freq_rounded =
261 tegra_emc_round_rate_updown(emc_target, true);
262 break;
263
264 case TEGRA210:
265 emc_freq_lower = (unsigned long)
266 tegra_emc_round_rate_updown(emc_target, false);
267 emc_freq_upper = (unsigned long)
268 tegra_emc_round_rate_updown(emc_target, true);
269
270 /* round to the nearest frequency step */
271 if (emc_target < (emc_freq_lower + emc_freq_upper) / 2)
272 emc_freq_rounded = emc_freq_lower;
273 else
274 emc_freq_rounded = emc_freq_upper;
275 break;
276
277 default:
278 /* a proper rounding function needs to be implemented
279 * for emc in t18x */
280 emc_freq_rounded = clk_round_rate(emc_clk, emc_target);
281 break;
282 }
283
284 /* only change the emc clock if new rounded frequency is different
285 * from previously set emc rate */
286 if (emc_freq_rounded != emc_params->freq_last_set) {
287 clk_set_rate(emc_clk, emc_freq_rounded);
288 emc_params->freq_last_set = emc_freq_rounded;
289 }
290}
291
292/*
293 * gk20a_tegra_prescale(profile, freq)
294 *
295 * This function informs EDP about changed constraints.
296 */
297
298static void gk20a_tegra_prescale(struct device *dev)
299{
300 struct gk20a *g = get_gk20a(dev);
301 u32 avg = 0;
302
303 nvgpu_pmu_load_norm(g, &avg);
304 tegra_edp_notify_gpu_load(avg, clk_get_rate(g->clk.tegra_clk));
305}
306
307/*
308 * gk20a_tegra_calibrate_emc()
309 *
310 */
311
312static void gk20a_tegra_calibrate_emc(struct device *dev,
313 struct gk20a_emc_params *emc_params)
314{
315 enum tegra_chipid cid = tegra_get_chip_id();
316 long gpu_bw, emc_bw;
317
318 /* store gpu bw based on soc */
319 switch (cid) {
320 case TEGRA210:
321 gpu_bw = TEGRA_GM20B_BW_PER_FREQ;
322 break;
323 case TEGRA124:
324 case TEGRA132:
325 gpu_bw = TEGRA_GK20A_BW_PER_FREQ;
326 break;
327 default:
328 gpu_bw = 0;
329 break;
330 }
331
332 /* TODO detect DDR type.
333 * Okay for now since DDR3 and DDR4 have the same BW ratio */
334 emc_bw = TEGRA_DDR3_BW_PER_FREQ;
335
336 /* Calculate the bandwidth ratio of gpu_freq <-> emc_freq
337 * NOTE the ratio must come out as an integer */
338 emc_params->bw_ratio = (gpu_bw / emc_bw);
339}
340
341#ifdef CONFIG_TEGRA_BWMGR
342#ifdef CONFIG_TEGRA_DVFS
343static void gm20b_bwmgr_set_rate(struct gk20a_platform *platform, bool enb)
344{
345 struct gk20a_scale_profile *profile = platform->g->scale_profile;
346 struct gk20a_emc_params *params;
347 unsigned long rate;
348
349 if (!profile || !profile->private_data)
350 return;
351
352 params = (struct gk20a_emc_params *)profile->private_data;
353 rate = (enb) ? params->freq_last_set : 0;
354 tegra_bwmgr_set_emc(params->bwmgr_cl, rate, TEGRA_BWMGR_SET_EMC_FLOOR);
355}
356#endif
357
358static void gm20b_tegra_postscale(struct device *dev, unsigned long freq)
359{
360 struct gk20a_platform *platform = dev_get_drvdata(dev);
361 struct gk20a_scale_profile *profile = platform->g->scale_profile;
362 struct gk20a_emc_params *emc_params;
363 unsigned long emc_rate;
364
365 if (!profile)
366 return;
367
368 emc_params = profile->private_data;
369 emc_rate = gk20a_tegra_get_emc_rate(get_gk20a(dev), emc_params);
370
371 if (emc_rate > tegra_bwmgr_get_max_emc_rate())
372 emc_rate = tegra_bwmgr_get_max_emc_rate();
373
374 emc_params->freq_last_set = emc_rate;
375 nvgpu_mutex_acquire(&platform->railgate_lock);
376 if (platform->is_railgated && platform->is_railgated(dev))
377 goto done;
378
379 tegra_bwmgr_set_emc(emc_params->bwmgr_cl, emc_rate,
380 TEGRA_BWMGR_SET_EMC_FLOOR);
381
382done:
383 nvgpu_mutex_release(&platform->railgate_lock);
384}
385
386#endif
387
388#if defined(CONFIG_TEGRA_DVFS)
389/*
390 * gk20a_tegra_is_railgated()
391 *
392 * Check status of gk20a power rail
393 */
394
395static bool gk20a_tegra_is_railgated(struct device *dev)
396{
397 struct gk20a *g = get_gk20a(dev);
398 struct gk20a_platform *platform = dev_get_drvdata(dev);
399 bool ret = false;
400
401 if (!nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
402 ret = !tegra_dvfs_is_rail_up(platform->gpu_rail);
403
404 return ret;
405}
406
407/*
408 * gm20b_tegra_railgate()
409 *
410 * Gate (disable) gm20b power rail
411 */
412
413static int gm20b_tegra_railgate(struct device *dev)
414{
415 struct gk20a *g = get_gk20a(dev);
416 struct gk20a_platform *platform = dev_get_drvdata(dev);
417 int ret = 0;
418
419 if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL) ||
420 !tegra_dvfs_is_rail_up(platform->gpu_rail))
421 return 0;
422
423 tegra_mc_flush(MC_CLIENT_GPU);
424
425 udelay(10);
426
427 /* enable clamp */
428 pmc_write(0x1, PMC_GPU_RG_CNTRL_0);
429 pmc_read(PMC_GPU_RG_CNTRL_0);
430
431 udelay(10);
432
433 platform->reset_assert(dev);
434
435 udelay(10);
436
437 /*
438 * GPCPLL is already disabled before entering this function; reference
439 * clocks are enabled until now - disable them just before rail gating
440 */
441 clk_disable_unprepare(platform->clk_reset);
442 clk_disable_unprepare(platform->clk[0]);
443 clk_disable_unprepare(platform->clk[1]);
444 if (platform->clk[3])
445 clk_disable_unprepare(platform->clk[3]);
446
447 udelay(10);
448
449 tegra_soctherm_gpu_tsens_invalidate(1);
450
451 if (tegra_dvfs_is_rail_up(platform->gpu_rail)) {
452 ret = tegra_dvfs_rail_power_down(platform->gpu_rail);
453 if (ret)
454 goto err_power_off;
455 } else
456 pr_info("No GPU regulator?\n");
457
458#ifdef CONFIG_TEGRA_BWMGR
459 gm20b_bwmgr_set_rate(platform, false);
460#endif
461
462 return 0;
463
464err_power_off:
465 nvgpu_err(platform->g, "Could not railgate GPU");
466 return ret;
467}
468
469
470/*
471 * gm20b_tegra_unrailgate()
472 *
473 * Ungate (enable) gm20b power rail
474 */
475
476static int gm20b_tegra_unrailgate(struct device *dev)
477{
478 struct gk20a_platform *platform = dev_get_drvdata(dev);
479 struct gk20a *g = platform->g;
480 int ret = 0;
481 bool first = false;
482
483 if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
484 return 0;
485
486 ret = tegra_dvfs_rail_power_up(platform->gpu_rail);
487 if (ret)
488 return ret;
489
490#ifdef CONFIG_TEGRA_BWMGR
491 gm20b_bwmgr_set_rate(platform, true);
492#endif
493
494 tegra_soctherm_gpu_tsens_invalidate(0);
495
496 if (!platform->clk_reset) {
497 platform->clk_reset = clk_get(dev, "gpu_gate");
498 if (IS_ERR(platform->clk_reset)) {
499 nvgpu_err(g, "fail to get gpu reset clk");
500 goto err_clk_on;
501 }
502 }
503
504 if (!first) {
505 ret = clk_prepare_enable(platform->clk_reset);
506 if (ret) {
507 nvgpu_err(g, "could not turn on gpu_gate");
508 goto err_clk_on;
509 }
510
511 ret = clk_prepare_enable(platform->clk[0]);
512 if (ret) {
513 nvgpu_err(g, "could not turn on gpu pll");
514 goto err_clk_on;
515 }
516 ret = clk_prepare_enable(platform->clk[1]);
517 if (ret) {
518 nvgpu_err(g, "could not turn on pwr clock");
519 goto err_clk_on;
520 }
521
522 if (platform->clk[3]) {
523 ret = clk_prepare_enable(platform->clk[3]);
524 if (ret) {
525 nvgpu_err(g, "could not turn on fuse clock");
526 goto err_clk_on;
527 }
528 }
529 }
530
531 udelay(10);
532
533 platform->reset_assert(dev);
534
535 udelay(10);
536
537 pmc_write(0, PMC_GPU_RG_CNTRL_0);
538 pmc_read(PMC_GPU_RG_CNTRL_0);
539
540 udelay(10);
541
542 clk_disable(platform->clk_reset);
543 platform->reset_deassert(dev);
544 clk_enable(platform->clk_reset);
545
546 /* Flush MC after boot/railgate/SC7 */
547 tegra_mc_flush(MC_CLIENT_GPU);
548
549 udelay(10);
550
551 tegra_mc_flush_done(MC_CLIENT_GPU);
552
553 udelay(10);
554
555 return 0;
556
557err_clk_on:
558 tegra_dvfs_rail_power_down(platform->gpu_rail);
559
560 return ret;
561}
562#endif
563
564
565static struct {
566 char *name;
567 unsigned long default_rate;
568} tegra_gk20a_clocks[] = {
569 {"gpu_ref", UINT_MAX},
570 {"pll_p_out5", 204000000},
571 {"emc", UINT_MAX},
572 {"fuse", UINT_MAX},
573};
574
575
576
577/*
578 * gk20a_tegra_get_clocks()
579 *
580 * This function finds clocks in tegra platform and populates
581 * the clock information to gk20a platform data.
582 */
583
584static int gk20a_tegra_get_clocks(struct device *dev)
585{
586 struct gk20a_platform *platform = dev_get_drvdata(dev);
587 char devname[16];
588 unsigned int i;
589 int ret = 0;
590
591 BUG_ON(GK20A_CLKS_MAX < ARRAY_SIZE(tegra_gk20a_clocks));
592
593 snprintf(devname, sizeof(devname), "tegra_%s", dev_name(dev));
594
595 platform->num_clks = 0;
596 for (i = 0; i < ARRAY_SIZE(tegra_gk20a_clocks); i++) {
597 long rate = tegra_gk20a_clocks[i].default_rate;
598 struct clk *c;
599
600 c = clk_get_sys(devname, tegra_gk20a_clocks[i].name);
601 if (IS_ERR(c)) {
602 ret = PTR_ERR(c);
603 goto err_get_clock;
604 }
605 rate = clk_round_rate(c, rate);
606 clk_set_rate(c, rate);
607 platform->clk[i] = c;
608 }
609 platform->num_clks = i;
610
611 return 0;
612
613err_get_clock:
614
615 while (i--)
616 clk_put(platform->clk[i]);
617 return ret;
618}
619
620static int gk20a_tegra_reset_assert(struct device *dev)
621{
622 struct gk20a_platform *platform = gk20a_get_platform(dev);
623
624 if (!platform->clk_reset)
625 platform->clk_reset = platform->clk[0];
626
627 tegra_periph_reset_assert(platform->clk_reset);
628
629 return 0;
630}
631
632static int gk20a_tegra_reset_deassert(struct device *dev)
633{
634 struct gk20a_platform *platform = gk20a_get_platform(dev);
635
636 if (!platform->clk_reset)
637 return -EINVAL;
638
639 tegra_periph_reset_deassert(platform->clk_reset);
640
641 return 0;
642}
643
644#if defined(CONFIG_RESET_CONTROLLER) && defined(CONFIG_COMMON_CLK)
645static int gm20b_tegra_reset_assert(struct device *dev)
646{
647 struct gk20a_platform *platform = gk20a_get_platform(dev);
648
649 if (!platform->reset_control) {
650 WARN(1, "Reset control not initialized\n");
651 return -ENOSYS;
652 }
653
654 return reset_control_assert(platform->reset_control);
655}
656
657static int gm20b_tegra_reset_deassert(struct device *dev)
658{
659 struct gk20a_platform *platform = gk20a_get_platform(dev);
660
661 if (!platform->reset_control) {
662 WARN(1, "Reset control not initialized\n");
663 return -ENOSYS;
664 }
665
666 return reset_control_deassert(platform->reset_control);
667}
668#endif
669
670static void gk20a_tegra_scale_init(struct device *dev)
671{
672 struct gk20a_platform *platform = gk20a_get_platform(dev);
673 struct gk20a_scale_profile *profile = platform->g->scale_profile;
674 struct gk20a_emc_params *emc_params;
675
676 if (!profile)
677 return;
678
679 emc_params = nvgpu_kzalloc(platform->g, sizeof(*emc_params));
680 if (!emc_params)
681 return;
682
683 emc_params->freq_last_set = -1;
684 gk20a_tegra_calibrate_emc(dev, emc_params);
685
686#ifdef CONFIG_TEGRA_BWMGR
687 emc_params->bwmgr_cl = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_GPU);
688 if (!emc_params->bwmgr_cl) {
689 gk20a_dbg_info("%s Missing GPU BWMGR client\n", __func__);
690 return;
691 }
692#endif
693
694 profile->private_data = emc_params;
695}
696
697static void gk20a_tegra_scale_exit(struct device *dev)
698{
699 struct gk20a_platform *platform = dev_get_drvdata(dev);
700 struct gk20a_scale_profile *profile = platform->g->scale_profile;
701 struct gk20a_emc_params *emc_params;
702
703 if (!profile)
704 return;
705
706 emc_params = profile->private_data;
707#ifdef CONFIG_TEGRA_BWMGR
708 tegra_bwmgr_unregister(emc_params->bwmgr_cl);
709#endif
710
711 nvgpu_kfree(platform->g, profile->private_data);
712}
713
714void gk20a_tegra_debug_dump(struct device *dev)
715{
716#ifdef CONFIG_TEGRA_GK20A_NVHOST
717 struct gk20a_platform *platform = gk20a_get_platform(dev);
718 struct gk20a *g = platform->g;
719
720 if (g->nvhost_dev)
721 nvgpu_nvhost_debug_dump_device(g->nvhost_dev);
722#endif
723}
724
725int gk20a_tegra_busy(struct device *dev)
726{
727#ifdef CONFIG_TEGRA_GK20A_NVHOST
728 struct gk20a_platform *platform = gk20a_get_platform(dev);
729 struct gk20a *g = platform->g;
730
731 if (g->nvhost_dev)
732 return nvgpu_nvhost_module_busy_ext(g->nvhost_dev);
733#endif
734 return 0;
735}
736
737void gk20a_tegra_idle(struct device *dev)
738{
739#ifdef CONFIG_TEGRA_GK20A_NVHOST
740 struct gk20a_platform *platform = gk20a_get_platform(dev);
741 struct gk20a *g = platform->g;
742
743 if (g->nvhost_dev)
744 nvgpu_nvhost_module_idle_ext(g->nvhost_dev);
745#endif
746}
747
748void gk20a_tegra_init_secure_alloc(struct gk20a *g)
749{
750 g->ops.mm.secure_alloc = gk20a_tegra_secure_alloc;
751}
752
753#ifdef CONFIG_COMMON_CLK
754static struct clk *gk20a_clk_get(struct gk20a *g)
755{
756 if (!g->clk.tegra_clk) {
757 struct clk *clk;
758 char clk_dev_id[32];
759 struct device *dev = dev_from_gk20a(g);
760
761 snprintf(clk_dev_id, 32, "tegra_%s", dev_name(dev));
762
763 clk = clk_get_sys(clk_dev_id, "gpu");
764 if (IS_ERR(clk)) {
765 nvgpu_err(g, "fail to get tegra gpu clk %s/gpu\n",
766 clk_dev_id);
767 return NULL;
768 }
769 g->clk.tegra_clk = clk;
770 }
771
772 return g->clk.tegra_clk;
773}
774
775static int gm20b_clk_prepare_ops(struct clk_hw *hw)
776{
777 struct clk_gk20a *clk = to_clk_gk20a(hw);
778 return gm20b_clk_prepare(clk);
779}
780
781static void gm20b_clk_unprepare_ops(struct clk_hw *hw)
782{
783 struct clk_gk20a *clk = to_clk_gk20a(hw);
784 gm20b_clk_unprepare(clk);
785}
786
787static int gm20b_clk_is_prepared_ops(struct clk_hw *hw)
788{
789 struct clk_gk20a *clk = to_clk_gk20a(hw);
790 return gm20b_clk_is_prepared(clk);
791}
792
793static unsigned long gm20b_recalc_rate_ops(struct clk_hw *hw, unsigned long parent_rate)
794{
795 struct clk_gk20a *clk = to_clk_gk20a(hw);
796 return gm20b_recalc_rate(clk, parent_rate);
797}
798
799static int gm20b_gpcclk_set_rate_ops(struct clk_hw *hw, unsigned long rate,
800 unsigned long parent_rate)
801{
802 struct clk_gk20a *clk = to_clk_gk20a(hw);
803 return gm20b_gpcclk_set_rate(clk, rate, parent_rate);
804}
805
806static long gm20b_round_rate_ops(struct clk_hw *hw, unsigned long rate,
807 unsigned long *parent_rate)
808{
809 struct clk_gk20a *clk = to_clk_gk20a(hw);
810 return gm20b_round_rate(clk, rate, parent_rate);
811}
812
813static const struct clk_ops gm20b_clk_ops = {
814 .prepare = gm20b_clk_prepare_ops,
815 .unprepare = gm20b_clk_unprepare_ops,
816 .is_prepared = gm20b_clk_is_prepared_ops,
817 .recalc_rate = gm20b_recalc_rate_ops,
818 .set_rate = gm20b_gpcclk_set_rate_ops,
819 .round_rate = gm20b_round_rate_ops,
820};
821
822static int gm20b_register_gpcclk(struct gk20a *g)
823{
824 const char *parent_name = "pllg_ref";
825 struct clk_gk20a *clk = &g->clk;
826 struct clk_init_data init;
827 struct clk *c;
828 int err = 0;
829
830 /* make sure the clock is available */
831 if (!gk20a_clk_get(g))
832 return -ENOSYS;
833
834 err = gm20b_init_clk_setup_sw(g);
835 if (err)
836 return err;
837
838 init.name = "gpcclk";
839 init.ops = &gm20b_clk_ops;
840 init.parent_names = &parent_name;
841 init.num_parents = 1;
842 init.flags = 0;
843
844 /* Data in .init is copied by clk_register(), so stack variable OK */
845 clk->hw.init = &init;
846 c = clk_register(g->dev, &clk->hw);
847 if (IS_ERR(c)) {
848 nvgpu_err(g, "Failed to register GPCPLL clock");
849 return -EINVAL;
850 }
851
852 clk->g = g;
853 clk_register_clkdev(c, "gpcclk", "gpcclk");
854
855 return err;
856}
857#endif /* CONFIG_COMMON_CLK */
858
859static int gk20a_tegra_probe(struct device *dev)
860{
861 struct gk20a_platform *platform = dev_get_drvdata(dev);
862 struct device_node *np = dev->of_node;
863 bool joint_xpu_rail = false;
864 int ret;
865
866#ifdef CONFIG_COMMON_CLK
867 /* DVFS is not guaranteed to be initialized at the time of probe on
868 * kernels with Common Clock Framework enabled.
869 */
870 if (!platform->gpu_rail) {
871 platform->gpu_rail = tegra_dvfs_get_rail_by_name(GPU_RAIL_NAME);
872 if (!platform->gpu_rail) {
873 gk20a_dbg_info("deferring probe no gpu_rail\n");
874 return -EPROBE_DEFER;
875 }
876 }
877
878 if (!tegra_dvfs_is_rail_ready(platform->gpu_rail)) {
879 gk20a_dbg_info("deferring probe gpu_rail not ready\n");
880 return -EPROBE_DEFER;
881 }
882#endif
883
884#ifdef CONFIG_TEGRA_GK20A_NVHOST
885 ret = nvgpu_get_nvhost_dev(platform->g);
886 if (ret)
887 return ret;
888#endif
889
890#ifdef CONFIG_OF
891 joint_xpu_rail = of_property_read_bool(of_chosen,
892 "nvidia,tegra-joint_xpu_rail");
893#endif
894
895 if (joint_xpu_rail) {
896 gk20a_dbg_info("XPU rails are joint\n");
897 platform->g->can_railgate = false;
898 }
899
900 platform->g->clk.gpc_pll.id = GK20A_GPC_PLL;
901 if (tegra_get_chip_id() == TEGRA210) {
902 /* WAR for bug 1547668: Disable railgating and scaling
903 irrespective of platform data if the rework was not made. */
904 np = of_find_node_by_path("/gpu-dvfs-rework");
905 if (!(np && of_device_is_available(np))) {
906 platform->devfreq_governor = "";
907 dev_warn(dev, "board does not support scaling");
908 }
909 platform->g->clk.gpc_pll.id = GM20B_GPC_PLL_B1;
910#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
911 if (tegra_chip_get_revision() > TEGRA210_REVISION_A04p)
912 platform->g->clk.gpc_pll.id = GM20B_GPC_PLL_C1;
913#endif
914 }
915
916 if (tegra_get_chip_id() == TEGRA132)
917 platform->soc_name = "tegra13x";
918
919 gk20a_tegra_get_clocks(dev);
920 nvgpu_linux_init_clk_support(platform->g);
921 gk20a_tegra_init_secure_alloc(platform->g);
922
923 if (platform->clk_register) {
924 ret = platform->clk_register(platform->g);
925 if (ret)
926 return ret;
927 }
928
929#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
930 pmc = ioremap(TEGRA_PMC_BASE, 4096);
931#endif
932
933 return 0;
934}
935
936static int gk20a_tegra_late_probe(struct device *dev)
937{
938 /* Cause early VPR resize */
939 gk20a_tegra_secure_page_alloc(dev);
940
941 /* Initialise tegra specific scaling quirks */
942 gk20a_tegra_scale_init(dev);
943
944 return 0;
945}
946
947static int gk20a_tegra_remove(struct device *dev)
948{
949 /* deinitialise tegra specific scaling quirks */
950 gk20a_tegra_scale_exit(dev);
951
952#ifdef CONFIG_TEGRA_GK20A_NVHOST
953 nvgpu_free_nvhost_dev(get_gk20a(dev));
954#endif
955
956 return 0;
957}
958
959static int gk20a_tegra_suspend(struct device *dev)
960{
961 tegra_edp_notify_gpu_load(0, 0);
962 return 0;
963}
964
965#if defined(CONFIG_COMMON_CLK)
966static long gk20a_round_clk_rate(struct device *dev, unsigned long rate)
967{
968 struct gk20a_platform *platform = gk20a_get_platform(dev);
969 struct gk20a *g = platform->g;
970
971 /* make sure the clock is available */
972 if (!gk20a_clk_get(g))
973 return rate;
974
975 return clk_round_rate(clk_get_parent(g->clk.tegra_clk), rate);
976}
977
978static int gk20a_clk_get_freqs(struct device *dev,
979 unsigned long **freqs, int *num_freqs)
980{
981 struct gk20a_platform *platform = gk20a_get_platform(dev);
982 struct gk20a *g = platform->g;
983
984 /* make sure the clock is available */
985 if (!gk20a_clk_get(g))
986 return -ENOSYS;
987
988 return tegra_dvfs_get_freqs(clk_get_parent(g->clk.tegra_clk),
989 freqs, num_freqs);
990}
991#endif
992
993
994struct gk20a_platform gk20a_tegra_platform = {
995 .has_syncpoints = true,
996 .aggressive_sync_destroy_thresh = 64,
997
998 /* power management configuration */
999 .railgate_delay_init = 500,
1000 .can_railgate_init = true,
1001 .can_elpg_init = true,
1002 .enable_slcg = true,
1003 .enable_blcg = true,
1004 .enable_elcg = true,
1005 .enable_elpg = true,
1006 .enable_aelpg = true,
1007 .ptimer_src_freq = 12000000,
1008
1009 .force_reset_in_do_idle = false,
1010
1011 .default_big_page_size = SZ_128K,
1012
1013 .ch_wdt_timeout_ms = 7000,
1014
1015 .probe = gk20a_tegra_probe,
1016 .late_probe = gk20a_tegra_late_probe,
1017 .remove = gk20a_tegra_remove,
1018
1019 /* power management callbacks */
1020 .suspend = gk20a_tegra_suspend,
1021
1022 .busy = gk20a_tegra_busy,
1023 .idle = gk20a_tegra_idle,
1024
1025 .reset_assert = gk20a_tegra_reset_assert,
1026 .reset_deassert = gk20a_tegra_reset_deassert,
1027
1028 /* frequency scaling configuration */
1029 .prescale = gk20a_tegra_prescale,
1030 .postscale = gk20a_tegra_postscale,
1031 .devfreq_governor = "nvhost_podgov",
1032 .qos_notify = gk20a_scale_qos_notify,
1033
1034 .dump_platform_dependencies = gk20a_tegra_debug_dump,
1035
1036 .soc_name = "tegra12x",
1037
1038 .unified_memory = true,
1039};
1040
1041struct gk20a_platform gm20b_tegra_platform = {
1042 .has_syncpoints = true,
1043 .aggressive_sync_destroy_thresh = 64,
1044
1045 /* power management configuration */
1046 .railgate_delay_init = 500,
1047 .can_railgate_init = true,
1048 .can_elpg_init = true,
1049 .enable_slcg = true,
1050 .enable_blcg = true,
1051 .enable_elcg = true,
1052 .enable_elpg = true,
1053 .enable_aelpg = true,
1054 .ptimer_src_freq = 19200000,
1055
1056 .force_reset_in_do_idle = false,
1057
1058 .default_big_page_size = SZ_128K,
1059
1060 .ch_wdt_timeout_ms = 5000,
1061
1062 .probe = gk20a_tegra_probe,
1063 .late_probe = gk20a_tegra_late_probe,
1064 .remove = gk20a_tegra_remove,
1065 /* power management callbacks */
1066 .suspend = gk20a_tegra_suspend,
1067
1068#if defined(CONFIG_TEGRA_DVFS)
1069 .railgate = gm20b_tegra_railgate,
1070 .unrailgate = gm20b_tegra_unrailgate,
1071 .is_railgated = gk20a_tegra_is_railgated,
1072#endif
1073
1074 .busy = gk20a_tegra_busy,
1075 .idle = gk20a_tegra_idle,
1076
1077#if defined(CONFIG_RESET_CONTROLLER) && defined(CONFIG_COMMON_CLK)
1078 .reset_assert = gm20b_tegra_reset_assert,
1079 .reset_deassert = gm20b_tegra_reset_deassert,
1080#else
1081 .reset_assert = gk20a_tegra_reset_assert,
1082 .reset_deassert = gk20a_tegra_reset_deassert,
1083#endif
1084
1085#if defined(CONFIG_COMMON_CLK)
1086 .clk_round_rate = gk20a_round_clk_rate,
1087 .get_clk_freqs = gk20a_clk_get_freqs,
1088#endif
1089
1090#ifdef CONFIG_COMMON_CLK
1091 .clk_register = gm20b_register_gpcclk,
1092#endif
1093
1094 /* frequency scaling configuration */
1095 .prescale = gk20a_tegra_prescale,
1096#ifdef CONFIG_TEGRA_BWMGR
1097 .postscale = gm20b_tegra_postscale,
1098#else
1099 .postscale = gk20a_tegra_postscale,
1100#endif
1101 .devfreq_governor = "nvhost_podgov",
1102 .qos_notify = gk20a_scale_qos_notify,
1103
1104 .dump_platform_dependencies = gk20a_tegra_debug_dump,
1105
1106 .has_cde = true,
1107
1108 .soc_name = "tegra21x",
1109
1110 .unified_memory = true,
1111};
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.h b/drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.h
new file mode 100644
index 00000000..1aa7c1e3
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/platform_gk20a_tegra.h
@@ -0,0 +1,25 @@
1/*
2 * GK20A Platform (SoC) Interface
3 *
4 * Copyright (c) 2014-2017, 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
16#ifndef _NVGPU_PLATFORM_GK20A_TEGRA_H_
17#define _NVGPU_PLATFORM_GK20A_TEGRA_H_
18
19struct device;
20struct gk20a;
21
22void gk20a_tegra_init_secure_alloc(struct gk20a *g);
23int gk20a_tegra_secure_page_alloc(struct device *dev);
24
25#endif
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c
new file mode 100644
index 00000000..5980c592
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c
@@ -0,0 +1,786 @@
1/*
2 * GP10B Tegra Platform Interface
3 *
4 * Copyright (c) 2014-2017, 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
16#include <linux/of_platform.h>
17#include <linux/debugfs.h>
18#include <linux/dma-buf.h>
19#include <linux/nvmap.h>
20#include <linux/reset.h>
21#include <linux/platform/tegra/emc_bwmgr.h>
22
23#include <uapi/linux/nvgpu.h>
24
25#include <soc/tegra/tegra_bpmp.h>
26#include <soc/tegra/tegra_powergate.h>
27
28#include <nvgpu/kmem.h>
29#include <nvgpu/bug.h>
30#include <nvgpu/enabled.h>
31#include <nvgpu/hashtable.h>
32#include <nvgpu/nvhost.h>
33
34#include "clk.h"
35
36#include "gk20a/platform_gk20a.h"
37#include "gk20a/gk20a.h"
38#include "gk20a/gk20a_scale.h"
39
40#include "platform_gk20a_tegra.h"
41#include "gp10b/gp10b_sysfs.h"
42#include "gp10b/platform_gp10b.h"
43#include "platform_gp10b_tegra.h"
44
45#include <nvgpu/hw/gp10b/hw_gr_gp10b.h>
46#include <nvgpu/hw/gp10b/hw_ltc_gp10b.h>
47
48/* Select every GP10B_FREQ_SELECT_STEP'th frequency from h/w table */
49#define GP10B_FREQ_SELECT_STEP 8
50/* Max number of freq supported in h/w */
51#define GP10B_MAX_SUPPORTED_FREQS 120
52static unsigned long
53gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS / GP10B_FREQ_SELECT_STEP];
54
55#define TEGRA_GP10B_BW_PER_FREQ 64
56#define TEGRA_DDR4_BW_PER_FREQ 16
57
58#define EMC_BW_RATIO (TEGRA_GP10B_BW_PER_FREQ / TEGRA_DDR4_BW_PER_FREQ)
59
60static struct {
61 char *name;
62 unsigned long default_rate;
63} tegra_gp10b_clocks[] = {
64 {"gpu", 1000000000},
65 {"gpu_sys", 204000000} };
66
67static void gr_gp10b_remove_sysfs(struct device *dev);
68
69/*
70 * gp10b_tegra_get_clocks()
71 *
72 * This function finds clocks in tegra platform and populates
73 * the clock information to gp10b platform data.
74 */
75
76int gp10b_tegra_get_clocks(struct device *dev)
77{
78 struct gk20a *g = get_gk20a(dev);
79 struct gk20a_platform *platform = dev_get_drvdata(dev);
80 unsigned int i;
81
82 if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
83 return 0;
84
85 platform->num_clks = 0;
86 for (i = 0; i < ARRAY_SIZE(tegra_gp10b_clocks); i++) {
87 long rate = tegra_gp10b_clocks[i].default_rate;
88 struct clk *c;
89
90 c = clk_get(dev, tegra_gp10b_clocks[i].name);
91 if (IS_ERR(c)) {
92 nvgpu_err(platform->g, "cannot get clock %s",
93 tegra_gp10b_clocks[i].name);
94 } else {
95 clk_set_rate(c, rate);
96 platform->clk[i] = c;
97 }
98 }
99 platform->num_clks = i;
100
101 return 0;
102}
103
104static void gp10b_tegra_scale_init(struct device *dev)
105{
106 struct gk20a_platform *platform = gk20a_get_platform(dev);
107 struct gk20a_scale_profile *profile = platform->g->scale_profile;
108 struct tegra_bwmgr_client *bwmgr_handle;
109
110 if (!profile)
111 return;
112
113 bwmgr_handle = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_GPU);
114 if (!bwmgr_handle)
115 return;
116
117 profile->private_data = (void *)bwmgr_handle;
118}
119
120static void gp10b_tegra_scale_exit(struct device *dev)
121{
122 struct gk20a_platform *platform = gk20a_get_platform(dev);
123 struct gk20a_scale_profile *profile = platform->g->scale_profile;
124
125 if (profile)
126 tegra_bwmgr_unregister(
127 (struct tegra_bwmgr_client *)profile->private_data);
128}
129
130static int gp10b_tegra_probe(struct device *dev)
131{
132 struct gk20a_platform *platform = dev_get_drvdata(dev);
133#ifdef CONFIG_TEGRA_GK20A_NVHOST
134 int ret;
135
136 ret = nvgpu_get_nvhost_dev(platform->g);
137 if (ret)
138 return ret;
139#endif
140
141 platform->bypass_smmu = !device_is_iommuable(dev);
142 platform->disable_bigpage = platform->bypass_smmu;
143
144 platform->g->gr.t18x.ctx_vars.dump_ctxsw_stats_on_channel_close
145 = false;
146 platform->g->gr.t18x.ctx_vars.dump_ctxsw_stats_on_channel_close
147 = false;
148
149 platform->g->gr.t18x.ctx_vars.force_preemption_gfxp = false;
150 platform->g->gr.t18x.ctx_vars.force_preemption_cilp = false;
151
152 gp10b_tegra_get_clocks(dev);
153 nvgpu_linux_init_clk_support(platform->g);
154 gk20a_tegra_init_secure_alloc(platform->g);
155
156 return 0;
157}
158
159static int gp10b_tegra_late_probe(struct device *dev)
160{
161 /* Cause early VPR resize */
162 gk20a_tegra_secure_page_alloc(dev);
163
164 /*Create GP10B specific sysfs*/
165 gp10b_create_sysfs(dev);
166
167 /* Initialise tegra specific scaling quirks */
168 gp10b_tegra_scale_init(dev);
169 return 0;
170}
171
172int gp10b_tegra_remove(struct device *dev)
173{
174 gr_gp10b_remove_sysfs(dev);
175 /*Remove GP10B specific sysfs*/
176 gp10b_remove_sysfs(dev);
177
178 /* deinitialise tegra specific scaling quirks */
179 gp10b_tegra_scale_exit(dev);
180
181#ifdef CONFIG_TEGRA_GK20A_NVHOST
182 nvgpu_free_nvhost_dev(get_gk20a(dev));
183#endif
184
185 return 0;
186}
187
188static bool gp10b_tegra_is_railgated(struct device *dev)
189{
190 bool ret = false;
191
192 if (tegra_bpmp_running())
193 ret = !tegra_powergate_is_powered(TEGRA186_POWER_DOMAIN_GPU);
194
195 return ret;
196}
197
198static int gp10b_tegra_railgate(struct device *dev)
199{
200 struct gk20a_platform *platform = gk20a_get_platform(dev);
201 struct gk20a_scale_profile *profile = platform->g->scale_profile;
202
203 /* remove emc frequency floor */
204 if (profile)
205 tegra_bwmgr_set_emc(
206 (struct tegra_bwmgr_client *)profile->private_data,
207 0, TEGRA_BWMGR_SET_EMC_FLOOR);
208
209 if (tegra_bpmp_running() &&
210 tegra_powergate_is_powered(TEGRA186_POWER_DOMAIN_GPU)) {
211 int i;
212 for (i = 0; i < platform->num_clks; i++) {
213 if (platform->clk[i])
214 clk_disable_unprepare(platform->clk[i]);
215 }
216 tegra_powergate_partition(TEGRA186_POWER_DOMAIN_GPU);
217 }
218 return 0;
219}
220
221static int gp10b_tegra_unrailgate(struct device *dev)
222{
223 int ret = 0;
224 struct gk20a_platform *platform = gk20a_get_platform(dev);
225 struct gk20a_scale_profile *profile = platform->g->scale_profile;
226
227 if (tegra_bpmp_running()) {
228 int i;
229 ret = tegra_unpowergate_partition(TEGRA186_POWER_DOMAIN_GPU);
230 for (i = 0; i < platform->num_clks; i++) {
231 if (platform->clk[i])
232 clk_prepare_enable(platform->clk[i]);
233 }
234 }
235
236 /* to start with set emc frequency floor to max rate*/
237 if (profile)
238 tegra_bwmgr_set_emc(
239 (struct tegra_bwmgr_client *)profile->private_data,
240 tegra_bwmgr_get_max_emc_rate(),
241 TEGRA_BWMGR_SET_EMC_FLOOR);
242 return ret;
243}
244
245static int gp10b_tegra_suspend(struct device *dev)
246{
247 return 0;
248}
249
250int gp10b_tegra_reset_assert(struct device *dev)
251{
252 struct gk20a_platform *platform = gk20a_get_platform(dev);
253 int ret = 0;
254
255 if (!platform->reset_control)
256 return -EINVAL;
257
258 ret = reset_control_assert(platform->reset_control);
259
260 return ret;
261}
262
263int gp10b_tegra_reset_deassert(struct device *dev)
264{
265 struct gk20a_platform *platform = gk20a_get_platform(dev);
266 int ret = 0;
267
268 if (!platform->reset_control)
269 return -EINVAL;
270
271 ret = reset_control_deassert(platform->reset_control);
272
273 return ret;
274}
275
276static void gp10b_tegra_prescale(struct device *dev)
277{
278 struct gk20a *g = get_gk20a(dev);
279 u32 avg = 0;
280
281 gk20a_dbg_fn("");
282
283 nvgpu_pmu_load_norm(g, &avg);
284
285 gk20a_dbg_fn("done");
286}
287
288static void gp10b_tegra_postscale(struct device *pdev,
289 unsigned long freq)
290{
291 struct gk20a_platform *platform = gk20a_get_platform(pdev);
292 struct gk20a_scale_profile *profile = platform->g->scale_profile;
293 struct gk20a *g = get_gk20a(pdev);
294 unsigned long emc_rate;
295
296 gk20a_dbg_fn("");
297 if (profile && !gp10b_tegra_is_railgated(pdev)) {
298 unsigned long emc_scale;
299
300 if (freq <= gp10b_freq_table[0])
301 emc_scale = 0;
302 else
303 emc_scale = g->emc3d_ratio;
304
305 emc_rate = (freq * EMC_BW_RATIO * emc_scale) / 1000;
306
307 if (emc_rate > tegra_bwmgr_get_max_emc_rate())
308 emc_rate = tegra_bwmgr_get_max_emc_rate();
309
310 tegra_bwmgr_set_emc(
311 (struct tegra_bwmgr_client *)profile->private_data,
312 emc_rate, TEGRA_BWMGR_SET_EMC_FLOOR);
313 }
314 gk20a_dbg_fn("done");
315}
316
317static long gp10b_round_clk_rate(struct device *dev, unsigned long rate)
318{
319 struct gk20a *g = get_gk20a(dev);
320 struct gk20a_scale_profile *profile = g->scale_profile;
321 unsigned long *freq_table = profile->devfreq_profile.freq_table;
322 int max_states = profile->devfreq_profile.max_state;
323 int i;
324
325 for (i = 0; i < max_states; ++i)
326 if (freq_table[i] >= rate)
327 return freq_table[i];
328
329 return freq_table[max_states - 1];
330}
331
332static int gp10b_clk_get_freqs(struct device *dev,
333 unsigned long **freqs, int *num_freqs)
334{
335 struct gk20a_platform *platform = gk20a_get_platform(dev);
336 unsigned long max_rate;
337 unsigned long new_rate = 0, prev_rate = 0;
338 int i = 0, freq_counter = 0;
339
340 max_rate = clk_round_rate(platform->clk[0], (UINT_MAX - 1));
341
342 /*
343 * Walk the h/w frequency table and only select
344 * GP10B_FREQ_SELECT_STEP'th frequencies and
345 * add MAX freq to last
346 */
347 for (; i < GP10B_MAX_SUPPORTED_FREQS; ++i) {
348 prev_rate = new_rate;
349 new_rate = clk_round_rate(platform->clk[0], prev_rate + 1);
350
351 if (i % GP10B_FREQ_SELECT_STEP == 0 ||
352 new_rate == max_rate) {
353 gp10b_freq_table[freq_counter++] = new_rate;
354
355 if (new_rate == max_rate)
356 break;
357 }
358 }
359
360 WARN_ON(i == GP10B_MAX_SUPPORTED_FREQS);
361
362 /* Fill freq table */
363 *freqs = gp10b_freq_table;
364 *num_freqs = freq_counter;
365
366 gk20a_dbg_info("min rate: %ld max rate: %ld num_of_freq %d\n",
367 gp10b_freq_table[0], max_rate, *num_freqs);
368
369 return 0;
370}
371
372struct gk20a_platform gp10b_tegra_platform = {
373 .has_syncpoints = true,
374
375 /* power management configuration */
376 .railgate_delay_init = 500,
377
378 /* power management configuration */
379 .can_railgate_init = true,
380 .enable_elpg = true,
381 .can_elpg_init = true,
382 .enable_blcg = true,
383 .enable_slcg = true,
384 .enable_elcg = true,
385 .enable_aelpg = true,
386
387 /* ptimer src frequency in hz*/
388 .ptimer_src_freq = 31250000,
389
390 .ch_wdt_timeout_ms = 5000,
391
392 .probe = gp10b_tegra_probe,
393 .late_probe = gp10b_tegra_late_probe,
394 .remove = gp10b_tegra_remove,
395
396 /* power management callbacks */
397 .suspend = gp10b_tegra_suspend,
398 .railgate = gp10b_tegra_railgate,
399 .unrailgate = gp10b_tegra_unrailgate,
400 .is_railgated = gp10b_tegra_is_railgated,
401
402 .busy = gk20a_tegra_busy,
403 .idle = gk20a_tegra_idle,
404
405 .dump_platform_dependencies = gk20a_tegra_debug_dump,
406
407 .default_big_page_size = SZ_64K,
408
409 .has_cde = true,
410
411 .clk_round_rate = gp10b_round_clk_rate,
412 .get_clk_freqs = gp10b_clk_get_freqs,
413
414 /* frequency scaling configuration */
415 .prescale = gp10b_tegra_prescale,
416 .postscale = gp10b_tegra_postscale,
417 .devfreq_governor = "nvhost_podgov",
418
419 .qos_notify = gk20a_scale_qos_notify,
420
421 .reset_assert = gp10b_tegra_reset_assert,
422 .reset_deassert = gp10b_tegra_reset_deassert,
423
424 .force_reset_in_do_idle = false,
425
426 .soc_name = "tegra18x",
427
428 .unified_memory = true,
429};
430
431
432#define ECC_STAT_NAME_MAX_SIZE 100
433
434
435static DEFINE_HASHTABLE(ecc_hash_table, 5);
436
437static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array;
438static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array;
439
440static struct device_attribute *dev_attr_sm_shm_ecc_sec_count_array;
441static struct device_attribute *dev_attr_sm_shm_ecc_sed_count_array;
442static struct device_attribute *dev_attr_sm_shm_ecc_ded_count_array;
443
444static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe0_count_array;
445static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe0_count_array;
446static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe0_count_array;
447static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe0_count_array;
448static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe1_count_array;
449static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe1_count_array;
450static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe1_count_array;
451static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe1_count_array;
452
453static struct device_attribute *dev_attr_l2_ecc_sec_count_array;
454static struct device_attribute *dev_attr_l2_ecc_ded_count_array;
455
456
457static u32 gen_ecc_hash_key(char *str)
458{
459 int i = 0;
460 u32 hash_key = 0;
461
462 while (str[i]) {
463 hash_key += (u32)(str[i]);
464 i++;
465 };
466
467 return hash_key;
468}
469
470static ssize_t ecc_stat_show(struct device *dev,
471 struct device_attribute *attr,
472 char *buf)
473{
474 const char *ecc_stat_full_name = attr->attr.name;
475 const char *ecc_stat_base_name;
476 unsigned int hw_unit;
477 struct gk20a_ecc_stat *ecc_stat;
478 u32 hash_key;
479
480 if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) {
481 ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]);
482 } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) {
483 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]);
484 } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) {
485 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]);
486 } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) {
487 ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]);
488 } else {
489 return snprintf(buf,
490 PAGE_SIZE,
491 "Error: Invalid ECC stat name!\n");
492 }
493
494 hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name);
495 hash_for_each_possible(ecc_hash_table,
496 ecc_stat,
497 hash_node,
498 hash_key) {
499 if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit]))
500 return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]);
501 }
502
503 return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n");
504}
505
506int gr_gp10b_ecc_stat_create(struct device *dev,
507 int is_l2,
508 char *ecc_stat_name,
509 struct gk20a_ecc_stat *ecc_stat,
510 struct device_attribute **dev_attr_array)
511{
512 struct gk20a *g = get_gk20a(dev);
513 char *ltc_unit_name = "ltc";
514 char *gr_unit_name = "gpc0_tpc";
515 int num_hw_units = 0;
516
517 if (is_l2)
518 num_hw_units = g->ltc_count;
519 else
520 num_hw_units = g->gr.tpc_count;
521
522
523 return gp10b_ecc_stat_create(dev, num_hw_units,
524 is_l2 ? ltc_unit_name : gr_unit_name,
525 ecc_stat_name,
526 ecc_stat,
527 dev_attr_array);
528}
529
530int gp10b_ecc_stat_create(struct device *dev,
531 int num_hw_units,
532 char *ecc_unit_name,
533 char *ecc_stat_name,
534 struct gk20a_ecc_stat *ecc_stat,
535 struct device_attribute **__dev_attr_array)
536{
537 int error = 0;
538 struct gk20a *g = get_gk20a(dev);
539 int hw_unit = 0;
540 u32 hash_key = 0;
541 struct device_attribute *dev_attr_array;
542
543 /* Allocate arrays */
544 dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) *
545 num_hw_units);
546 ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_hw_units);
547 ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_hw_units);
548 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
549 ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) *
550 ECC_STAT_NAME_MAX_SIZE);
551 }
552
553 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
554 /* Fill in struct device_attribute members */
555 snprintf(ecc_stat->names[hw_unit],
556 ECC_STAT_NAME_MAX_SIZE,
557 "%s%d_%s",
558 ecc_unit_name,
559 hw_unit,
560 ecc_stat_name);
561
562 sysfs_attr_init(&dev_attr_array[hw_unit].attr);
563 dev_attr_array[hw_unit].attr.name = ecc_stat->names[hw_unit];
564 dev_attr_array[hw_unit].attr.mode = VERIFY_OCTAL_PERMISSIONS(S_IRUGO);
565 dev_attr_array[hw_unit].show = ecc_stat_show;
566 dev_attr_array[hw_unit].store = NULL;
567
568 /* Create sysfs file */
569 error |= device_create_file(dev, &dev_attr_array[hw_unit]);
570 }
571
572 /* Add hash table entry */
573 hash_key = gen_ecc_hash_key(ecc_stat_name);
574 hash_add(ecc_hash_table,
575 &ecc_stat->hash_node,
576 hash_key);
577
578 *__dev_attr_array = dev_attr_array;
579
580 return error;
581}
582
583void gr_gp10b_ecc_stat_remove(struct device *dev,
584 int is_l2,
585 struct gk20a_ecc_stat *ecc_stat,
586 struct device_attribute *dev_attr_array)
587{
588 struct gk20a *g = get_gk20a(dev);
589 int num_hw_units = 0;
590
591 if (is_l2)
592 num_hw_units = g->ltc_count;
593 else
594 num_hw_units = g->gr.tpc_count;
595
596 gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array);
597}
598
599void gp10b_ecc_stat_remove(struct device *dev,
600 int num_hw_units,
601 struct gk20a_ecc_stat *ecc_stat,
602 struct device_attribute *dev_attr_array)
603{
604 struct gk20a *g = get_gk20a(dev);
605 int hw_unit = 0;
606
607 /* Remove sysfs files */
608 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
609 device_remove_file(dev, &dev_attr_array[hw_unit]);
610 }
611
612 /* Remove hash table entry */
613 hash_del(&ecc_stat->hash_node);
614
615 /* Free arrays */
616 nvgpu_kfree(g, ecc_stat->counters);
617 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
618 nvgpu_kfree(g, ecc_stat->names[hw_unit]);
619 }
620 nvgpu_kfree(g, ecc_stat->names);
621 nvgpu_kfree(g, dev_attr_array);
622}
623
624void gr_gp10b_create_sysfs(struct device *dev)
625{
626 int error = 0;
627 struct gk20a *g = get_gk20a(dev);
628
629 /* This stat creation function is called on GR init. GR can get
630 initialized multiple times but we only need to create the ECC
631 stats once. Therefore, add the following check to avoid
632 creating duplicate stat sysfs nodes. */
633 if (g->ecc.gr.t18x.sm_lrf_single_err_count.counters != NULL)
634 return;
635
636 error |= gr_gp10b_ecc_stat_create(dev,
637 0,
638 "sm_lrf_ecc_single_err_count",
639 &g->ecc.gr.t18x.sm_lrf_single_err_count,
640 &dev_attr_sm_lrf_ecc_single_err_count_array);
641 error |= gr_gp10b_ecc_stat_create(dev,
642 0,
643 "sm_lrf_ecc_double_err_count",
644 &g->ecc.gr.t18x.sm_lrf_double_err_count,
645 &dev_attr_sm_lrf_ecc_double_err_count_array);
646
647 error |= gr_gp10b_ecc_stat_create(dev,
648 0,
649 "sm_shm_ecc_sec_count",
650 &g->ecc.gr.t18x.sm_shm_sec_count,
651 &dev_attr_sm_shm_ecc_sec_count_array);
652 error |= gr_gp10b_ecc_stat_create(dev,
653 0,
654 "sm_shm_ecc_sed_count",
655 &g->ecc.gr.t18x.sm_shm_sed_count,
656 &dev_attr_sm_shm_ecc_sed_count_array);
657 error |= gr_gp10b_ecc_stat_create(dev,
658 0,
659 "sm_shm_ecc_ded_count",
660 &g->ecc.gr.t18x.sm_shm_ded_count,
661 &dev_attr_sm_shm_ecc_ded_count_array);
662
663 error |= gr_gp10b_ecc_stat_create(dev,
664 0,
665 "tex_ecc_total_sec_pipe0_count",
666 &g->ecc.gr.t18x.tex_total_sec_pipe0_count,
667 &dev_attr_tex_ecc_total_sec_pipe0_count_array);
668 error |= gr_gp10b_ecc_stat_create(dev,
669 0,
670 "tex_ecc_total_ded_pipe0_count",
671 &g->ecc.gr.t18x.tex_total_ded_pipe0_count,
672 &dev_attr_tex_ecc_total_ded_pipe0_count_array);
673 error |= gr_gp10b_ecc_stat_create(dev,
674 0,
675 "tex_ecc_unique_sec_pipe0_count",
676 &g->ecc.gr.t18x.tex_unique_sec_pipe0_count,
677 &dev_attr_tex_ecc_unique_sec_pipe0_count_array);
678 error |= gr_gp10b_ecc_stat_create(dev,
679 0,
680 "tex_ecc_unique_ded_pipe0_count",
681 &g->ecc.gr.t18x.tex_unique_ded_pipe0_count,
682 &dev_attr_tex_ecc_unique_ded_pipe0_count_array);
683 error |= gr_gp10b_ecc_stat_create(dev,
684 0,
685 "tex_ecc_total_sec_pipe1_count",
686 &g->ecc.gr.t18x.tex_total_sec_pipe1_count,
687 &dev_attr_tex_ecc_total_sec_pipe1_count_array);
688 error |= gr_gp10b_ecc_stat_create(dev,
689 0,
690 "tex_ecc_total_ded_pipe1_count",
691 &g->ecc.gr.t18x.tex_total_ded_pipe1_count,
692 &dev_attr_tex_ecc_total_ded_pipe1_count_array);
693 error |= gr_gp10b_ecc_stat_create(dev,
694 0,
695 "tex_ecc_unique_sec_pipe1_count",
696 &g->ecc.gr.t18x.tex_unique_sec_pipe1_count,
697 &dev_attr_tex_ecc_unique_sec_pipe1_count_array);
698 error |= gr_gp10b_ecc_stat_create(dev,
699 0,
700 "tex_ecc_unique_ded_pipe1_count",
701 &g->ecc.gr.t18x.tex_unique_ded_pipe1_count,
702 &dev_attr_tex_ecc_unique_ded_pipe1_count_array);
703
704 error |= gr_gp10b_ecc_stat_create(dev,
705 1,
706 "lts0_ecc_sec_count",
707 &g->ecc.gr.t18x.l2_sec_count,
708 &dev_attr_l2_ecc_sec_count_array);
709 error |= gr_gp10b_ecc_stat_create(dev,
710 1,
711 "lts0_ecc_ded_count",
712 &g->ecc.gr.t18x.l2_ded_count,
713 &dev_attr_l2_ecc_ded_count_array);
714
715 if (error)
716 dev_err(dev, "Failed to create sysfs attributes!\n");
717}
718
719static void gr_gp10b_remove_sysfs(struct device *dev)
720{
721 struct gk20a *g = get_gk20a(dev);
722
723 gr_gp10b_ecc_stat_remove(dev,
724 0,
725 &g->ecc.gr.t18x.sm_lrf_single_err_count,
726 dev_attr_sm_lrf_ecc_single_err_count_array);
727 gr_gp10b_ecc_stat_remove(dev,
728 0,
729 &g->ecc.gr.t18x.sm_lrf_double_err_count,
730 dev_attr_sm_lrf_ecc_double_err_count_array);
731
732 gr_gp10b_ecc_stat_remove(dev,
733 0,
734 &g->ecc.gr.t18x.sm_shm_sec_count,
735 dev_attr_sm_shm_ecc_sec_count_array);
736 gr_gp10b_ecc_stat_remove(dev,
737 0,
738 &g->ecc.gr.t18x.sm_shm_sed_count,
739 dev_attr_sm_shm_ecc_sed_count_array);
740 gr_gp10b_ecc_stat_remove(dev,
741 0,
742 &g->ecc.gr.t18x.sm_shm_ded_count,
743 dev_attr_sm_shm_ecc_ded_count_array);
744
745 gr_gp10b_ecc_stat_remove(dev,
746 0,
747 &g->ecc.gr.t18x.tex_total_sec_pipe0_count,
748 dev_attr_tex_ecc_total_sec_pipe0_count_array);
749 gr_gp10b_ecc_stat_remove(dev,
750 0,
751 &g->ecc.gr.t18x.tex_total_ded_pipe0_count,
752 dev_attr_tex_ecc_total_ded_pipe0_count_array);
753 gr_gp10b_ecc_stat_remove(dev,
754 0,
755 &g->ecc.gr.t18x.tex_unique_sec_pipe0_count,
756 dev_attr_tex_ecc_unique_sec_pipe0_count_array);
757 gr_gp10b_ecc_stat_remove(dev,
758 0,
759 &g->ecc.gr.t18x.tex_unique_ded_pipe0_count,
760 dev_attr_tex_ecc_unique_ded_pipe0_count_array);
761 gr_gp10b_ecc_stat_remove(dev,
762 0,
763 &g->ecc.gr.t18x.tex_total_sec_pipe1_count,
764 dev_attr_tex_ecc_total_sec_pipe1_count_array);
765 gr_gp10b_ecc_stat_remove(dev,
766 0,
767 &g->ecc.gr.t18x.tex_total_ded_pipe1_count,
768 dev_attr_tex_ecc_total_ded_pipe1_count_array);
769 gr_gp10b_ecc_stat_remove(dev,
770 0,
771 &g->ecc.gr.t18x.tex_unique_sec_pipe1_count,
772 dev_attr_tex_ecc_unique_sec_pipe1_count_array);
773 gr_gp10b_ecc_stat_remove(dev,
774 0,
775 &g->ecc.gr.t18x.tex_unique_ded_pipe1_count,
776 dev_attr_tex_ecc_unique_ded_pipe1_count_array);
777
778 gr_gp10b_ecc_stat_remove(dev,
779 1,
780 &g->ecc.gr.t18x.l2_sec_count,
781 dev_attr_l2_ecc_sec_count_array);
782 gr_gp10b_ecc_stat_remove(dev,
783 1,
784 &g->ecc.gr.t18x.l2_ded_count,
785 dev_attr_l2_ecc_ded_count_array);
786}
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h
new file mode 100644
index 00000000..74db60d1
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef _PLATFORM_GP10B_TEGRA_H_
18#define _PLATFORM_GP10B_TEGRA_H_
19
20#include "gp10b/gr_gp10b.h"
21
22int gr_gp10b_ecc_stat_create(struct device *dev,
23 int is_l2,
24 char *ecc_stat_name,
25 struct gk20a_ecc_stat *ecc_stat,
26 struct device_attribute **dev_attr_array);
27int gp10b_ecc_stat_create(struct device *dev,
28 int hw_units,
29 char *ecc_unit_name,
30 char *ecc_stat_name,
31 struct gk20a_ecc_stat *ecc_stat,
32 struct device_attribute **dev_attr_array);
33
34void gr_gp10b_ecc_stat_remove(struct device *dev,
35 int is_l2,
36 struct gk20a_ecc_stat *ecc_stat,
37 struct device_attribute *dev_attr_array);
38
39void gp10b_ecc_stat_remove(struct device *dev,
40 int hw_units,
41 struct gk20a_ecc_stat *ecc_stat,
42 struct device_attribute *dev_attr_array);
43
44int gp10b_tegra_remove(struct device *dev);
45
46#endif