summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2015-06-23 17:49:12 -0400
committerTerje Bergstrom <tbergstrom@nvidia.com>2015-07-07 11:23:32 -0400
commit16aaae648b4f5d236b597fd4d5d9bcda8d52078f (patch)
tree3efabbdc64ec8ac71dd37cab88691b8ba18d2f2c /drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c
parent0c25c820d751f4b2bbaffac15701d7084649d71e (diff)
gpu: nvgpu: Implement own rail gating code
Move rail gating sequence to happen in nvgpu driver instead of piggybacking on Tegra power gating APIs. Bug 200115454 Change-Id: I8514686c7b137f200021b05ead7157d0883bddc5 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/761991
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c270
1 files changed, 261 insertions, 9 deletions
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
44extern struct device tegra_vpr_dev; 49extern 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
56static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
57static inline u32 pmc_read(unsigned long reg)
58{
59 return readl(pmc + reg);
60}
61
62static 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
292static bool gk20a_tegra_is_railgated(struct platform_device *pdev) 308static 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
308static int gk20a_tegra_railgate(struct platform_device *pdev) 325static 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
366err_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
377static 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
421err_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
322static int gk20a_tegra_unrailgate(struct platform_device *pdev) 432static 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
491err_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
503static 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
572err_clk_on:
573 tegra_dvfs_rail_power_down(platform->gpu_rail);
574
327 return ret; 575 return ret;
328} 576}
577#endif
329 578
330static struct { 579static 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,