diff options
Diffstat (limited to 'drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.c')
-rw-r--r-- | drivers/gpu/nvgpu/tegra/linux/platform_gk20a_tegra.c | 1111 |
1 files changed, 0 insertions, 1111 deletions
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 | }; | ||