diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2017-06-19 17:17:03 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-06-20 22:14:15 -0400 |
commit | d0ea8fe969b2a8f7509621103c1ead83187b798b (patch) | |
tree | b95eb51dffcdfff4510e7980a031721a057931f7 /drivers/gpu/nvgpu/tegra/linux | |
parent | 7437fefa9016ab8904c79f521276f5c41e40c449 (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/tegra/linux')
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/clk.c | 133 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/clk.h | 22 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.c | 1111 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.h | 25 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.c | 786 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.h | 46 |
6 files changed, 0 insertions, 2123 deletions
diff --git a/drivers/gpu/nvgpu/tegra/linux/clk.c b/drivers/gpu/nvgpu/tegra/linux/clk.c deleted file mode 100644 index 775e5661..00000000 --- a/drivers/gpu/nvgpu/tegra/linux/clk.c +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
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 | |||
28 | static 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 | |||
52 | static 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 | |||
77 | static 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 | |||
88 | static 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 | |||
101 | static 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 | |||
108 | static 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 | |||
113 | static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk) | ||
114 | { | ||
115 | return clk_prepare_enable(clk->tegra_clk); | ||
116 | } | ||
117 | |||
118 | static void nvgpu_linux_disable_unprepare(struct clk_gk20a *clk) | ||
119 | { | ||
120 | clk_disable_unprepare(clk->tegra_clk); | ||
121 | } | ||
122 | |||
123 | void 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/tegra/linux/clk.h b/drivers/gpu/nvgpu/tegra/linux/clk.h deleted file mode 100644 index 614a7fd7..00000000 --- a/drivers/gpu/nvgpu/tegra/linux/clk.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
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 | |||
19 | struct gk20a; | ||
20 | void nvgpu_linux_init_clk_support(struct gk20a *g); | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.c deleted file mode 100644 index b0f6ee7d..00000000 --- a/drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.c +++ /dev/null | |||
@@ -1,1111 +0,0 @@ | |||
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 | |||
70 | extern struct device tegra_vpr_dev; | ||
71 | |||
72 | #ifdef CONFIG_TEGRA_BWMGR | ||
73 | struct gk20a_emc_params { | ||
74 | unsigned long bw_ratio; | ||
75 | unsigned long freq_last_set; | ||
76 | struct tegra_bwmgr_client *bwmgr_cl; | ||
77 | }; | ||
78 | #else | ||
79 | struct gk20a_emc_params { | ||
80 | unsigned long bw_ratio; | ||
81 | unsigned long freq_last_set; | ||
82 | }; | ||
83 | #endif | ||
84 | |||
85 | static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); | ||
86 | static inline u32 __maybe_unused pmc_read(unsigned long reg) | ||
87 | { | ||
88 | return readl(pmc + reg); | ||
89 | } | ||
90 | |||
91 | static 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 | |||
98 | static 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 | |||
110 | int 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 | |||
135 | static 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 | |||
151 | static 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 | |||
195 | fail_sgt: | ||
196 | nvgpu_kfree(platform->g, sgt); | ||
197 | fail: | ||
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 | |||
209 | static 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 | |||
238 | static 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 | |||
298 | static 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 | |||
312 | static 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 | ||
343 | static 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 | |||
358 | static 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 | |||
382 | done: | ||
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 | |||
395 | static 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 | |||
413 | static 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 | |||
464 | err_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 | |||
476 | static 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 | |||
557 | err_clk_on: | ||
558 | tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
559 | |||
560 | return ret; | ||
561 | } | ||
562 | #endif | ||
563 | |||
564 | |||
565 | static 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 | |||
584 | static 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 | |||
613 | err_get_clock: | ||
614 | |||
615 | while (i--) | ||
616 | clk_put(platform->clk[i]); | ||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | static 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 | |||
632 | static 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) | ||
645 | static 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 | |||
657 | static 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 | |||
670 | static 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 | |||
697 | static 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 | |||
714 | void 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 | |||
725 | int 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 | |||
737 | void 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 | |||
748 | void 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 | ||
754 | static 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 | |||
775 | static 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 | |||
781 | static 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 | |||
787 | static 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 | |||
793 | static 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 | |||
799 | static 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 | |||
806 | static 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 | |||
813 | static 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 | |||
822 | static 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 | |||
859 | static 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 | |||
936 | static 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 | |||
947 | static 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 | |||
959 | static 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) | ||
966 | static 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 | |||
978 | static 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 | |||
994 | struct 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 | |||
1041 | struct 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/tegra/linux/platform_gk20a_tegra.h b/drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.h deleted file mode 100644 index 1aa7c1e3..00000000 --- a/drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.h +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
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 | |||
19 | struct device; | ||
20 | struct gk20a; | ||
21 | |||
22 | void gk20a_tegra_init_secure_alloc(struct gk20a *g); | ||
23 | int gk20a_tegra_secure_page_alloc(struct device *dev); | ||
24 | |||
25 | #endif | ||
diff --git a/drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.c deleted file mode 100644 index 5980c592..00000000 --- a/drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.c +++ /dev/null | |||
@@ -1,786 +0,0 @@ | |||
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 | ||
52 | static unsigned long | ||
53 | gp10b_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 | |||
60 | static struct { | ||
61 | char *name; | ||
62 | unsigned long default_rate; | ||
63 | } tegra_gp10b_clocks[] = { | ||
64 | {"gpu", 1000000000}, | ||
65 | {"gpu_sys", 204000000} }; | ||
66 | |||
67 | static 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 | |||
76 | int 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 | |||
104 | static 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 | |||
120 | static 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 | |||
130 | static 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 | |||
159 | static 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 | |||
172 | int 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 | |||
188 | static 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 | |||
198 | static 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 | |||
221 | static 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 | |||
245 | static int gp10b_tegra_suspend(struct device *dev) | ||
246 | { | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | int 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 | |||
263 | int 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 | |||
276 | static 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 | |||
288 | static 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 | |||
317 | static 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 | |||
332 | static 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 | |||
372 | struct 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 | |||
435 | static DEFINE_HASHTABLE(ecc_hash_table, 5); | ||
436 | |||
437 | static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array; | ||
438 | static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array; | ||
439 | |||
440 | static struct device_attribute *dev_attr_sm_shm_ecc_sec_count_array; | ||
441 | static struct device_attribute *dev_attr_sm_shm_ecc_sed_count_array; | ||
442 | static struct device_attribute *dev_attr_sm_shm_ecc_ded_count_array; | ||
443 | |||
444 | static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe0_count_array; | ||
445 | static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe0_count_array; | ||
446 | static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe0_count_array; | ||
447 | static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe0_count_array; | ||
448 | static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe1_count_array; | ||
449 | static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe1_count_array; | ||
450 | static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe1_count_array; | ||
451 | static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe1_count_array; | ||
452 | |||
453 | static struct device_attribute *dev_attr_l2_ecc_sec_count_array; | ||
454 | static struct device_attribute *dev_attr_l2_ecc_ded_count_array; | ||
455 | |||
456 | |||
457 | static 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 | |||
470 | static 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 | |||
506 | int 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 | |||
530 | int 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 | |||
583 | void 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 | |||
599 | void 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 | |||
624 | void 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 | |||
719 | static 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/tegra/linux/platform_gp10b_tegra.h b/drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.h deleted file mode 100644 index 74db60d1..00000000 --- a/drivers/gpu/nvgpu/tegra/linux/platform_gp10b_tegra.h +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
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 | |||
22 | int 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); | ||
27 | int 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 | |||
34 | void 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 | |||
39 | void 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 | |||
44 | int gp10b_tegra_remove(struct device *dev); | ||
45 | |||
46 | #endif | ||