diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/platform_gk20a.h | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | 270 |
2 files changed, 262 insertions, 9 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h index f142cb9f..29c88f44 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h | |||
@@ -175,6 +175,7 @@ struct gk20a_platform { | |||
175 | int (*reset_assert)(struct platform_device *pdev); | 175 | int (*reset_assert)(struct platform_device *pdev); |
176 | int (*reset_deassert)(struct platform_device *pdev); | 176 | int (*reset_deassert)(struct platform_device *pdev); |
177 | struct clk *clk_reset; | 177 | struct clk *clk_reset; |
178 | struct dvfs_rail *gpu_rail; | ||
178 | 179 | ||
179 | bool virtual_dev; | 180 | bool virtual_dev; |
180 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION | 181 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION |
diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c index 80dfce54..5e07ac55 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | |||
@@ -20,13 +20,16 @@ | |||
20 | #include <linux/debugfs.h> | 20 | #include <linux/debugfs.h> |
21 | #include <linux/tegra-powergate.h> | 21 | #include <linux/tegra-powergate.h> |
22 | #include <linux/platform_data/tegra_edp.h> | 22 | #include <linux/platform_data/tegra_edp.h> |
23 | #include <linux/delay.h> | ||
23 | #include <uapi/linux/nvgpu.h> | 24 | #include <uapi/linux/nvgpu.h> |
24 | #include <linux/dma-buf.h> | 25 | #include <linux/dma-buf.h> |
25 | #include <linux/nvmap.h> | 26 | #include <linux/nvmap.h> |
26 | #include <linux/tegra_pm_domains.h> | 27 | #include <linux/tegra_pm_domains.h> |
28 | #include <linux/tegra_soctherm.h> | ||
27 | #include <linux/platform/tegra/clock.h> | 29 | #include <linux/platform/tegra/clock.h> |
28 | #include <linux/platform/tegra/dvfs.h> | 30 | #include <linux/platform/tegra/dvfs.h> |
29 | #include <linux/platform/tegra/common.h> | 31 | #include <linux/platform/tegra/common.h> |
32 | #include <linux/platform/tegra/mc.h> | ||
30 | #include <linux/clk/tegra.h> | 33 | #include <linux/clk/tegra.h> |
31 | 34 | ||
32 | #include <linux/platform/tegra/tegra_emc.h> | 35 | #include <linux/platform/tegra/tegra_emc.h> |
@@ -40,6 +43,8 @@ | |||
40 | #define TEGRA_GM20B_BW_PER_FREQ 64 | 43 | #define TEGRA_GM20B_BW_PER_FREQ 64 |
41 | #define TEGRA_DDR3_BW_PER_FREQ 16 | 44 | #define TEGRA_DDR3_BW_PER_FREQ 16 |
42 | #define TEGRA_DDR4_BW_PER_FREQ 16 | 45 | #define TEGRA_DDR4_BW_PER_FREQ 16 |
46 | #define MC_CLIENT_GPU 34 | ||
47 | #define PMC_GPU_RG_CNTRL_0 0x2d4 | ||
43 | 48 | ||
44 | extern struct device tegra_vpr_dev; | 49 | extern struct device tegra_vpr_dev; |
45 | 50 | ||
@@ -48,6 +53,16 @@ struct gk20a_emc_params { | |||
48 | long freq_last_set; | 53 | long freq_last_set; |
49 | }; | 54 | }; |
50 | 55 | ||
56 | static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); | ||
57 | static inline u32 pmc_read(unsigned long reg) | ||
58 | { | ||
59 | return readl(pmc + reg); | ||
60 | } | ||
61 | |||
62 | static inline void pmc_write(u32 val, unsigned long reg) | ||
63 | { | ||
64 | writel_relaxed(val, pmc + reg); | ||
65 | } | ||
51 | #define MHZ_TO_HZ(x) ((x) * 1000000) | 66 | #define MHZ_TO_HZ(x) ((x) * 1000000) |
52 | #define HZ_TO_MHZ(x) ((x) / 1000000) | 67 | #define HZ_TO_MHZ(x) ((x) / 1000000) |
53 | 68 | ||
@@ -283,6 +298,7 @@ static void gk20a_tegra_calibrate_emc(struct platform_device *pdev, | |||
283 | emc_params->bw_ratio = (gpu_bw / emc_bw); | 298 | emc_params->bw_ratio = (gpu_bw / emc_bw); |
284 | } | 299 | } |
285 | 300 | ||
301 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | ||
286 | /* | 302 | /* |
287 | * gk20a_tegra_is_railgated() | 303 | * gk20a_tegra_is_railgated() |
288 | * | 304 | * |
@@ -291,10 +307,11 @@ static void gk20a_tegra_calibrate_emc(struct platform_device *pdev, | |||
291 | 307 | ||
292 | static bool gk20a_tegra_is_railgated(struct platform_device *pdev) | 308 | static bool gk20a_tegra_is_railgated(struct platform_device *pdev) |
293 | { | 309 | { |
310 | struct gk20a_platform *platform = platform_get_drvdata(pdev); | ||
294 | bool ret = false; | 311 | bool ret = false; |
295 | 312 | ||
296 | if (!tegra_platform_is_linsim()) | 313 | if (!tegra_platform_is_linsim()) |
297 | ret = !tegra_powergate_is_powered(TEGRA_POWERGATE_GPU); | 314 | ret = !tegra_dvfs_is_rail_up(platform->gpu_rail); |
298 | 315 | ||
299 | return ret; | 316 | return ret; |
300 | } | 317 | } |
@@ -307,10 +324,103 @@ static bool gk20a_tegra_is_railgated(struct platform_device *pdev) | |||
307 | 324 | ||
308 | static int gk20a_tegra_railgate(struct platform_device *pdev) | 325 | static int gk20a_tegra_railgate(struct platform_device *pdev) |
309 | { | 326 | { |
310 | if (!tegra_platform_is_linsim() && | 327 | struct gk20a_platform *platform = platform_get_drvdata(pdev); |
311 | tegra_powergate_is_powered(TEGRA_POWERGATE_GPU)) | 328 | int ret = 0; |
312 | tegra_powergate_partition(TEGRA_POWERGATE_GPU); | 329 | |
330 | if (tegra_platform_is_linsim() || | ||
331 | !tegra_dvfs_is_rail_up(platform->gpu_rail)) | ||
332 | return 0; | ||
333 | |||
334 | tegra_mc_flush(MC_CLIENT_GPU); | ||
335 | |||
336 | udelay(10); | ||
337 | |||
338 | /* enable clamp */ | ||
339 | pmc_write(0x1, PMC_GPU_RG_CNTRL_0); | ||
340 | pmc_read(PMC_GPU_RG_CNTRL_0); | ||
341 | |||
342 | udelay(10); | ||
343 | |||
344 | platform->reset_assert(pdev); | ||
345 | |||
346 | udelay(10); | ||
347 | |||
348 | /* | ||
349 | * GPCPLL is already disabled before entering this function; reference | ||
350 | * clocks are enabled until now - disable them just before rail gating | ||
351 | */ | ||
352 | clk_disable(platform->clk[0]); | ||
353 | clk_disable(platform->clk[1]); | ||
354 | |||
355 | udelay(10); | ||
356 | |||
357 | if (tegra_dvfs_is_rail_up(platform->gpu_rail)) { | ||
358 | ret = tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
359 | if (ret) | ||
360 | goto err_power_off; | ||
361 | } else | ||
362 | pr_info("No GPU regulator?\n"); | ||
363 | |||
364 | return 0; | ||
365 | |||
366 | err_power_off: | ||
367 | gk20a_err(&pdev->dev, "Could not railgate GPU"); | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * gm20b_tegra_railgate() | ||
373 | * | ||
374 | * Gate (disable) gm20b power rail | ||
375 | */ | ||
376 | |||
377 | static int gm20b_tegra_railgate(struct platform_device *pdev) | ||
378 | { | ||
379 | struct gk20a_platform *platform = platform_get_drvdata(pdev); | ||
380 | int ret = 0; | ||
381 | |||
382 | if (tegra_platform_is_linsim() || | ||
383 | !tegra_dvfs_is_rail_up(platform->gpu_rail)) | ||
384 | return 0; | ||
385 | |||
386 | tegra_mc_flush(MC_CLIENT_GPU); | ||
387 | |||
388 | udelay(10); | ||
389 | |||
390 | /* enable clamp */ | ||
391 | pmc_write(0x1, PMC_GPU_RG_CNTRL_0); | ||
392 | pmc_read(PMC_GPU_RG_CNTRL_0); | ||
393 | |||
394 | udelay(10); | ||
395 | |||
396 | platform->reset_assert(pdev); | ||
397 | |||
398 | udelay(10); | ||
399 | |||
400 | /* | ||
401 | * GPCPLL is already disabled before entering this function; reference | ||
402 | * clocks are enabled until now - disable them just before rail gating | ||
403 | */ | ||
404 | clk_disable(platform->clk_reset); | ||
405 | clk_disable(platform->clk[0]); | ||
406 | clk_disable(platform->clk[1]); | ||
407 | |||
408 | udelay(10); | ||
409 | |||
410 | tegra_soctherm_gpu_tsens_invalidate(1); | ||
411 | |||
412 | if (tegra_dvfs_is_rail_up(platform->gpu_rail)) { | ||
413 | ret = tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
414 | if (ret) | ||
415 | goto err_power_off; | ||
416 | } else | ||
417 | pr_info("No GPU regulator?\n"); | ||
418 | |||
313 | return 0; | 419 | return 0; |
420 | |||
421 | err_power_off: | ||
422 | gk20a_err(&pdev->dev, "Could not railgate GPU"); | ||
423 | return ret; | ||
314 | } | 424 | } |
315 | 425 | ||
316 | /* | 426 | /* |
@@ -321,11 +431,150 @@ static int gk20a_tegra_railgate(struct platform_device *pdev) | |||
321 | 431 | ||
322 | static int gk20a_tegra_unrailgate(struct platform_device *pdev) | 432 | static int gk20a_tegra_unrailgate(struct platform_device *pdev) |
323 | { | 433 | { |
434 | struct gk20a_platform *platform = platform_get_drvdata(pdev); | ||
324 | int ret = 0; | 435 | int ret = 0; |
325 | if (!tegra_platform_is_linsim()) | 436 | bool first = false; |
326 | ret = tegra_unpowergate_partition(TEGRA_POWERGATE_GPU); | 437 | |
438 | if (tegra_platform_is_linsim()) | ||
439 | return 0; | ||
440 | |||
441 | if (!platform->gpu_rail) { | ||
442 | platform->gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu"); | ||
443 | if (IS_ERR_OR_NULL(platform->gpu_rail)) { | ||
444 | WARN(1, "No GPU regulator?\n"); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | first = true; | ||
448 | } | ||
449 | |||
450 | ret = tegra_dvfs_rail_power_up(platform->gpu_rail); | ||
451 | if (ret) | ||
452 | return ret; | ||
453 | |||
454 | if (!first) { | ||
455 | ret = clk_enable(platform->clk[0]); | ||
456 | if (ret) { | ||
457 | gk20a_err(&pdev->dev, "could not turn on gpu pll"); | ||
458 | goto err_clk_on; | ||
459 | } | ||
460 | ret = clk_enable(platform->clk[1]); | ||
461 | if (ret) { | ||
462 | gk20a_err(&pdev->dev, "could not turn on pwr clock"); | ||
463 | goto err_clk_on; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | udelay(10); | ||
468 | |||
469 | platform->reset_assert(pdev); | ||
470 | |||
471 | udelay(10); | ||
472 | |||
473 | pmc_write(0, PMC_GPU_RG_CNTRL_0); | ||
474 | pmc_read(PMC_GPU_RG_CNTRL_0); | ||
475 | |||
476 | udelay(10); | ||
477 | |||
478 | platform->reset_deassert(pdev); | ||
479 | |||
480 | /* Flush MC after boot/railgate/SC7 */ | ||
481 | tegra_mc_flush(MC_CLIENT_GPU); | ||
482 | |||
483 | udelay(10); | ||
484 | |||
485 | tegra_mc_flush_done(MC_CLIENT_GPU); | ||
486 | |||
487 | udelay(10); | ||
488 | |||
489 | return 0; | ||
490 | |||
491 | err_clk_on: | ||
492 | tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * gm20b_tegra_unrailgate() | ||
499 | * | ||
500 | * Ungate (enable) gm20b power rail | ||
501 | */ | ||
502 | |||
503 | static int gm20b_tegra_unrailgate(struct platform_device *pdev) | ||
504 | { | ||
505 | struct gk20a_platform *platform = platform_get_drvdata(pdev); | ||
506 | int ret = 0; | ||
507 | bool first = false; | ||
508 | |||
509 | if (tegra_platform_is_linsim()) | ||
510 | return 0; | ||
511 | |||
512 | if (!platform->gpu_rail) { | ||
513 | platform->gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu"); | ||
514 | if (IS_ERR_OR_NULL(platform->gpu_rail)) { | ||
515 | WARN(1, "No GPU regulator?\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | first = true; | ||
519 | } | ||
520 | |||
521 | ret = tegra_dvfs_rail_power_up(platform->gpu_rail); | ||
522 | if (ret) | ||
523 | return ret; | ||
524 | |||
525 | tegra_soctherm_gpu_tsens_invalidate(0); | ||
526 | |||
527 | if (!first) { | ||
528 | ret = clk_enable(platform->clk_reset); | ||
529 | if (ret) { | ||
530 | gk20a_err(&pdev->dev, "could not turn on gpu_gate"); | ||
531 | goto err_clk_on; | ||
532 | } | ||
533 | |||
534 | ret = clk_enable(platform->clk[0]); | ||
535 | if (ret) { | ||
536 | gk20a_err(&pdev->dev, "could not turn on gpu pll"); | ||
537 | goto err_clk_on; | ||
538 | } | ||
539 | ret = clk_enable(platform->clk[1]); | ||
540 | if (ret) { | ||
541 | gk20a_err(&pdev->dev, "could not turn on pwr clock"); | ||
542 | goto err_clk_on; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | udelay(10); | ||
547 | |||
548 | platform->reset_assert(pdev); | ||
549 | |||
550 | udelay(10); | ||
551 | |||
552 | pmc_write(0, PMC_GPU_RG_CNTRL_0); | ||
553 | pmc_read(PMC_GPU_RG_CNTRL_0); | ||
554 | |||
555 | udelay(10); | ||
556 | |||
557 | clk_disable(platform->clk_reset); | ||
558 | platform->reset_deassert(pdev); | ||
559 | clk_enable(platform->clk_reset); | ||
560 | |||
561 | /* Flush MC after boot/railgate/SC7 */ | ||
562 | tegra_mc_flush(MC_CLIENT_GPU); | ||
563 | |||
564 | udelay(10); | ||
565 | |||
566 | tegra_mc_flush_done(MC_CLIENT_GPU); | ||
567 | |||
568 | udelay(10); | ||
569 | |||
570 | return 0; | ||
571 | |||
572 | err_clk_on: | ||
573 | tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
574 | |||
327 | return ret; | 575 | return ret; |
328 | } | 576 | } |
577 | #endif | ||
329 | 578 | ||
330 | static struct { | 579 | static struct { |
331 | char *name; | 580 | char *name; |
@@ -565,9 +814,11 @@ struct gk20a_platform gk20a_tegra_platform = { | |||
565 | 814 | ||
566 | /* power management callbacks */ | 815 | /* power management callbacks */ |
567 | .suspend = gk20a_tegra_suspend, | 816 | .suspend = gk20a_tegra_suspend, |
817 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | ||
568 | .railgate = gk20a_tegra_railgate, | 818 | .railgate = gk20a_tegra_railgate, |
569 | .unrailgate = gk20a_tegra_unrailgate, | 819 | .unrailgate = gk20a_tegra_unrailgate, |
570 | .is_railgated = gk20a_tegra_is_railgated, | 820 | .is_railgated = gk20a_tegra_is_railgated, |
821 | #endif | ||
571 | 822 | ||
572 | .busy = gk20a_tegra_busy, | 823 | .busy = gk20a_tegra_busy, |
573 | .idle = gk20a_tegra_idle, | 824 | .idle = gk20a_tegra_idle, |
@@ -592,7 +843,6 @@ struct gk20a_platform gm20b_tegra_platform = { | |||
592 | /* power management configuration */ | 843 | /* power management configuration */ |
593 | .railgate_delay = 500, | 844 | .railgate_delay = 500, |
594 | .clockgate_delay = 50, | 845 | .clockgate_delay = 50, |
595 | /* Disable all power features for gm20b */ | ||
596 | .can_railgate = true, | 846 | .can_railgate = true, |
597 | .enable_slcg = true, | 847 | .enable_slcg = true, |
598 | .enable_blcg = true, | 848 | .enable_blcg = true, |
@@ -610,9 +860,11 @@ struct gk20a_platform gm20b_tegra_platform = { | |||
610 | 860 | ||
611 | /* power management callbacks */ | 861 | /* power management callbacks */ |
612 | .suspend = gk20a_tegra_suspend, | 862 | .suspend = gk20a_tegra_suspend, |
613 | .railgate = gk20a_tegra_railgate, | 863 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK |
614 | .unrailgate = gk20a_tegra_unrailgate, | 864 | .railgate = gm20b_tegra_railgate, |
865 | .unrailgate = gm20b_tegra_unrailgate, | ||
615 | .is_railgated = gk20a_tegra_is_railgated, | 866 | .is_railgated = gk20a_tegra_is_railgated, |
867 | #endif | ||
616 | 868 | ||
617 | .busy = gk20a_tegra_busy, | 869 | .busy = gk20a_tegra_busy, |
618 | .idle = gk20a_tegra_idle, | 870 | .idle = gk20a_tegra_idle, |