diff options
author | Peter Boonstoppel <pboonstoppel@nvidia.com> | 2016-10-06 00:53:18 -0400 |
---|---|---|
committer | Bharat Nihalani <bnihalani@nvidia.com> | 2016-10-17 05:09:28 -0400 |
commit | 2b593224dfbd93a34a31d5cd7654332f49d00d61 (patch) | |
tree | 260360fa47920eb590f5fcdfd5d361a206ba5078 | |
parent | fa6ab1943e2977c64f62ba5b9c05b6d7fba234f3 (diff) |
gpu: nvgpu: gm20b (un)railgate common clock support
Add support for GPU railgating using common clock framework and Tegra
DVFS on k4.4
Bug: 200233943
Change-Id: Ief9afd7a5bf3f447e9b91ab181f26dcefff0a8c8
Signed-off-by: Peter Boonstoppel <pboonstoppel@nvidia.com>
Reviewed-on: http://git-master/r/1232290
GVS: Gerrit_Virtual_Submit
Reviewed-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | 222 |
1 files changed, 137 insertions, 85 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c index 90ba54ea..933fe2d8 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <uapi/linux/nvgpu.h> | 23 | #include <uapi/linux/nvgpu.h> |
24 | #include <linux/dma-buf.h> | 24 | #include <linux/dma-buf.h> |
25 | #include <linux/nvmap.h> | 25 | #include <linux/nvmap.h> |
26 | #include <linux/reset.h> | ||
26 | #include <linux/tegra_soctherm.h> | 27 | #include <linux/tegra_soctherm.h> |
27 | #include <linux/platform/tegra/clock.h> | 28 | #include <linux/platform/tegra/clock.h> |
28 | #include <linux/platform/tegra/dvfs.h> | 29 | #include <linux/platform/tegra/dvfs.h> |
@@ -47,6 +48,12 @@ | |||
47 | #define MC_CLIENT_GPU 34 | 48 | #define MC_CLIENT_GPU 34 |
48 | #define PMC_GPU_RG_CNTRL_0 0x2d4 | 49 | #define PMC_GPU_RG_CNTRL_0 0x2d4 |
49 | 50 | ||
51 | #ifdef CONFIG_COMMON_CLK | ||
52 | #define GPU_RAIL_NAME "vdd-gpu" | ||
53 | #else | ||
54 | #define GPU_RAIL_NAME "vdd_gpu" | ||
55 | #endif | ||
56 | |||
50 | extern struct device tegra_vpr_dev; | 57 | extern struct device tegra_vpr_dev; |
51 | 58 | ||
52 | struct gk20a_emc_params { | 59 | struct gk20a_emc_params { |
@@ -304,23 +311,6 @@ static void gk20a_tegra_calibrate_emc(struct device *dev, | |||
304 | 311 | ||
305 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | 312 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK |
306 | /* | 313 | /* |
307 | * gk20a_tegra_is_railgated() | ||
308 | * | ||
309 | * Check status of gk20a power rail | ||
310 | */ | ||
311 | |||
312 | static bool gk20a_tegra_is_railgated(struct device *dev) | ||
313 | { | ||
314 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
315 | bool ret = false; | ||
316 | |||
317 | if (!(platform->is_fmodel)) | ||
318 | ret = !tegra_dvfs_is_rail_up(platform->gpu_rail); | ||
319 | |||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * gk20a_tegra_railgate() | 314 | * gk20a_tegra_railgate() |
325 | * | 315 | * |
326 | * Gate (disable) gk20a power rail | 316 | * Gate (disable) gk20a power rail |
@@ -372,60 +362,6 @@ err_power_off: | |||
372 | return ret; | 362 | return ret; |
373 | } | 363 | } |
374 | 364 | ||
375 | /* | ||
376 | * gm20b_tegra_railgate() | ||
377 | * | ||
378 | * Gate (disable) gm20b power rail | ||
379 | */ | ||
380 | |||
381 | static int gm20b_tegra_railgate(struct device *dev) | ||
382 | { | ||
383 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
384 | int ret = 0; | ||
385 | |||
386 | if (platform->is_fmodel || | ||
387 | !tegra_dvfs_is_rail_up(platform->gpu_rail)) | ||
388 | return 0; | ||
389 | |||
390 | tegra_mc_flush(MC_CLIENT_GPU); | ||
391 | |||
392 | udelay(10); | ||
393 | |||
394 | /* enable clamp */ | ||
395 | pmc_write(0x1, PMC_GPU_RG_CNTRL_0); | ||
396 | pmc_read(PMC_GPU_RG_CNTRL_0); | ||
397 | |||
398 | udelay(10); | ||
399 | |||
400 | platform->reset_assert(dev); | ||
401 | |||
402 | udelay(10); | ||
403 | |||
404 | /* | ||
405 | * GPCPLL is already disabled before entering this function; reference | ||
406 | * clocks are enabled until now - disable them just before rail gating | ||
407 | */ | ||
408 | clk_disable(platform->clk_reset); | ||
409 | clk_disable(platform->clk[0]); | ||
410 | clk_disable(platform->clk[1]); | ||
411 | |||
412 | udelay(10); | ||
413 | |||
414 | tegra_soctherm_gpu_tsens_invalidate(1); | ||
415 | |||
416 | if (tegra_dvfs_is_rail_up(platform->gpu_rail)) { | ||
417 | ret = tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
418 | if (ret) | ||
419 | goto err_power_off; | ||
420 | } else | ||
421 | pr_info("No GPU regulator?\n"); | ||
422 | |||
423 | return 0; | ||
424 | |||
425 | err_power_off: | ||
426 | gk20a_err(dev, "Could not railgate GPU"); | ||
427 | return ret; | ||
428 | } | ||
429 | 365 | ||
430 | /* | 366 | /* |
431 | * gk20a_tegra_unrailgate() | 367 | * gk20a_tegra_unrailgate() |
@@ -498,6 +434,84 @@ err_clk_on: | |||
498 | return ret; | 434 | return ret; |
499 | } | 435 | } |
500 | 436 | ||
437 | #endif | ||
438 | |||
439 | |||
440 | #if defined(CONFIG_TEGRA_CLK_FRAMEWORK) || defined(CONFIG_TEGRA_DVFS) | ||
441 | /* | ||
442 | * gk20a_tegra_is_railgated() | ||
443 | * | ||
444 | * Check status of gk20a power rail | ||
445 | */ | ||
446 | |||
447 | static bool gk20a_tegra_is_railgated(struct device *dev) | ||
448 | { | ||
449 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
450 | bool ret = false; | ||
451 | |||
452 | if (!platform->is_fmodel) | ||
453 | ret = !tegra_dvfs_is_rail_up(platform->gpu_rail); | ||
454 | |||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | |||
459 | /* | ||
460 | * gm20b_tegra_railgate() | ||
461 | * | ||
462 | * Gate (disable) gm20b power rail | ||
463 | */ | ||
464 | |||
465 | static int gm20b_tegra_railgate(struct device *dev) | ||
466 | { | ||
467 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
468 | int ret = 0; | ||
469 | |||
470 | if (platform->is_fmodel || | ||
471 | !tegra_dvfs_is_rail_up(platform->gpu_rail)) | ||
472 | return 0; | ||
473 | |||
474 | tegra_mc_flush(MC_CLIENT_GPU); | ||
475 | |||
476 | udelay(10); | ||
477 | |||
478 | /* enable clamp */ | ||
479 | pmc_write(0x1, PMC_GPU_RG_CNTRL_0); | ||
480 | pmc_read(PMC_GPU_RG_CNTRL_0); | ||
481 | |||
482 | udelay(10); | ||
483 | |||
484 | platform->reset_assert(dev); | ||
485 | |||
486 | udelay(10); | ||
487 | |||
488 | /* | ||
489 | * GPCPLL is already disabled before entering this function; reference | ||
490 | * clocks are enabled until now - disable them just before rail gating | ||
491 | */ | ||
492 | clk_disable_unprepare(platform->clk_reset); | ||
493 | clk_disable_unprepare(platform->clk[0]); | ||
494 | clk_disable_unprepare(platform->clk[1]); | ||
495 | |||
496 | udelay(10); | ||
497 | |||
498 | tegra_soctherm_gpu_tsens_invalidate(1); | ||
499 | |||
500 | if (tegra_dvfs_is_rail_up(platform->gpu_rail)) { | ||
501 | ret = tegra_dvfs_rail_power_down(platform->gpu_rail); | ||
502 | if (ret) | ||
503 | goto err_power_off; | ||
504 | } else | ||
505 | pr_info("No GPU regulator?\n"); | ||
506 | |||
507 | return 0; | ||
508 | |||
509 | err_power_off: | ||
510 | gk20a_err(dev, "Could not railgate GPU"); | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | |||
501 | /* | 515 | /* |
502 | * gm20b_tegra_unrailgate() | 516 | * gm20b_tegra_unrailgate() |
503 | * | 517 | * |
@@ -514,12 +528,14 @@ static int gm20b_tegra_unrailgate(struct device *dev) | |||
514 | return 0; | 528 | return 0; |
515 | 529 | ||
516 | if (!platform->gpu_rail) { | 530 | if (!platform->gpu_rail) { |
517 | platform->gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu"); | 531 | platform->gpu_rail = tegra_dvfs_get_rail_by_name(GPU_RAIL_NAME); |
518 | if (IS_ERR_OR_NULL(platform->gpu_rail)) { | 532 | if (IS_ERR_OR_NULL(platform->gpu_rail)) { |
519 | WARN(1, "No GPU regulator?\n"); | 533 | WARN(1, "No GPU regulator?\n"); |
520 | return -EINVAL; | 534 | return -EINVAL; |
521 | } | 535 | } |
536 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | ||
522 | first = true; | 537 | first = true; |
538 | #endif | ||
523 | } | 539 | } |
524 | 540 | ||
525 | ret = tegra_dvfs_rail_power_up(platform->gpu_rail); | 541 | ret = tegra_dvfs_rail_power_up(platform->gpu_rail); |
@@ -528,19 +544,27 @@ static int gm20b_tegra_unrailgate(struct device *dev) | |||
528 | 544 | ||
529 | tegra_soctherm_gpu_tsens_invalidate(0); | 545 | tegra_soctherm_gpu_tsens_invalidate(0); |
530 | 546 | ||
547 | if (!platform->clk_reset) { | ||
548 | platform->clk_reset = clk_get(dev, "gpu_gate"); | ||
549 | if (IS_ERR(platform->clk_reset)) { | ||
550 | gk20a_err(dev, "fail to get gpu reset clk\n"); | ||
551 | goto err_clk_on; | ||
552 | } | ||
553 | } | ||
554 | |||
531 | if (!first) { | 555 | if (!first) { |
532 | ret = clk_enable(platform->clk_reset); | 556 | ret = clk_prepare_enable(platform->clk_reset); |
533 | if (ret) { | 557 | if (ret) { |
534 | gk20a_err(dev, "could not turn on gpu_gate"); | 558 | gk20a_err(dev, "could not turn on gpu_gate"); |
535 | goto err_clk_on; | 559 | goto err_clk_on; |
536 | } | 560 | } |
537 | 561 | ||
538 | ret = clk_enable(platform->clk[0]); | 562 | ret = clk_prepare_enable(platform->clk[0]); |
539 | if (ret) { | 563 | if (ret) { |
540 | gk20a_err(dev, "could not turn on gpu pll"); | 564 | gk20a_err(dev, "could not turn on gpu pll"); |
541 | goto err_clk_on; | 565 | goto err_clk_on; |
542 | } | 566 | } |
543 | ret = clk_enable(platform->clk[1]); | 567 | ret = clk_prepare_enable(platform->clk[1]); |
544 | if (ret) { | 568 | if (ret) { |
545 | gk20a_err(dev, "could not turn on pwr clock"); | 569 | gk20a_err(dev, "could not turn on pwr clock"); |
546 | goto err_clk_on; | 570 | goto err_clk_on; |
@@ -580,13 +604,23 @@ err_clk_on: | |||
580 | } | 604 | } |
581 | #endif | 605 | #endif |
582 | 606 | ||
607 | |||
583 | static struct { | 608 | static struct { |
584 | char *name; | 609 | char *name; |
585 | unsigned long default_rate; | 610 | unsigned long default_rate; |
586 | } tegra_gk20a_clocks[] = { | 611 | } tegra_gk20a_clocks[] = { |
612 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | ||
587 | {"PLLG_ref", UINT_MAX}, | 613 | {"PLLG_ref", UINT_MAX}, |
588 | {"pwr", 204000000}, | 614 | {"pwr", 204000000}, |
589 | {"emc", UINT_MAX} }; | 615 | {"emc", UINT_MAX}, |
616 | #elif defined(CONFIG_COMMON_CLK) | ||
617 | {"gpu_ref", UINT_MAX}, | ||
618 | {"pll_p_out5", 204000000}, | ||
619 | {"emc", UINT_MAX}, | ||
620 | #endif | ||
621 | }; | ||
622 | |||
623 | |||
590 | 624 | ||
591 | /* | 625 | /* |
592 | * gk20a_tegra_get_clocks() | 626 | * gk20a_tegra_get_clocks() |
@@ -653,22 +687,31 @@ static int gk20a_tegra_reset_deassert(struct device *dev) | |||
653 | return 0; | 687 | return 0; |
654 | } | 688 | } |
655 | 689 | ||
690 | #if defined(CONFIG_RESET_CONTROLLER) && defined(CONFIG_COMMON_CLK) | ||
656 | static int gm20b_tegra_reset_assert(struct device *dev) | 691 | static int gm20b_tegra_reset_assert(struct device *dev) |
657 | { | 692 | { |
658 | struct gk20a_platform *platform = gk20a_get_platform(dev); | 693 | struct gk20a_platform *platform = gk20a_get_platform(dev); |
659 | 694 | ||
660 | if (!platform->clk_reset) { | 695 | if (!platform->reset_control) { |
661 | platform->clk_reset = clk_get(dev, "gpu_gate"); | 696 | WARN(1, "Reset control not initialized\n"); |
662 | if (IS_ERR(platform->clk_reset)) { | 697 | return -ENOSYS; |
663 | gk20a_err(dev, "fail to get gpu reset clk\n"); | ||
664 | return PTR_ERR(platform->clk_reset); | ||
665 | } | ||
666 | } | 698 | } |
667 | 699 | ||
668 | tegra_periph_reset_assert(platform->clk_reset); | 700 | return reset_control_assert(platform->reset_control); |
701 | } | ||
669 | 702 | ||
670 | return 0; | 703 | static int gm20b_tegra_reset_deassert(struct device *dev) |
704 | { | ||
705 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
706 | |||
707 | if (!platform->reset_control) { | ||
708 | WARN(1, "Reset control not initialized\n"); | ||
709 | return -ENOSYS; | ||
710 | } | ||
711 | |||
712 | return reset_control_deassert(platform->reset_control); | ||
671 | } | 713 | } |
714 | #endif | ||
672 | 715 | ||
673 | static void gk20a_tegra_scale_init(struct device *dev) | 716 | static void gk20a_tegra_scale_init(struct device *dev) |
674 | { | 717 | { |
@@ -778,6 +821,10 @@ static int gk20a_tegra_probe(struct device *dev) | |||
778 | 821 | ||
779 | gk20a_tegra_get_clocks(dev); | 822 | gk20a_tegra_get_clocks(dev); |
780 | 823 | ||
824 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) | ||
825 | pmc = ioremap(TEGRA_PMC_BASE, 4096); | ||
826 | #endif | ||
827 | |||
781 | return 0; | 828 | return 0; |
782 | } | 829 | } |
783 | 830 | ||
@@ -935,7 +982,7 @@ struct gk20a_platform gm20b_tegra_platform = { | |||
935 | 982 | ||
936 | /* power management callbacks */ | 983 | /* power management callbacks */ |
937 | .suspend = gk20a_tegra_suspend, | 984 | .suspend = gk20a_tegra_suspend, |
938 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | 985 | #if defined(CONFIG_TEGRA_CLK_FRAMEWORK) || defined(CONFIG_TEGRA_DVFS) |
939 | .railgate = gm20b_tegra_railgate, | 986 | .railgate = gm20b_tegra_railgate, |
940 | .unrailgate = gm20b_tegra_unrailgate, | 987 | .unrailgate = gm20b_tegra_unrailgate, |
941 | .is_railgated = gk20a_tegra_is_railgated, | 988 | .is_railgated = gk20a_tegra_is_railgated, |
@@ -944,8 +991,13 @@ struct gk20a_platform gm20b_tegra_platform = { | |||
944 | .busy = gk20a_tegra_busy, | 991 | .busy = gk20a_tegra_busy, |
945 | .idle = gk20a_tegra_idle, | 992 | .idle = gk20a_tegra_idle, |
946 | 993 | ||
994 | #if defined(CONFIG_RESET_CONTROLLER) && defined(CONFIG_COMMON_CLK) | ||
947 | .reset_assert = gm20b_tegra_reset_assert, | 995 | .reset_assert = gm20b_tegra_reset_assert, |
996 | .reset_deassert = gm20b_tegra_reset_deassert, | ||
997 | #else | ||
998 | .reset_assert = gk20a_tegra_reset_assert, | ||
948 | .reset_deassert = gk20a_tegra_reset_deassert, | 999 | .reset_deassert = gk20a_tegra_reset_deassert, |
1000 | #endif | ||
949 | 1001 | ||
950 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK | 1002 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK |
951 | .clk_get_rate = gk20a_get_clk_rate, | 1003 | .clk_get_rate = gk20a_get_clk_rate, |