summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2014-09-19 02:35:40 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:11:27 -0400
commit270029a760303443caaf2deb2c74cad67bbb7709 (patch)
treedf634223ee2d24f7eb9857ebff38f138a5c44786 /drivers/gpu/nvgpu/gm20b/clk_gm20b.c
parent293e7aa871393c3cd443e8d747019a69e48c77e7 (diff)
gpu: nvgpu: Support GPCPLL dynamic ramp in NA mode
Added support for GM20b GPCPLL dynamic ramp in NA mode that requires ramping of both integer NDIV and fractional SDM_DIN controls. If NA mode is enabled, dynamic ramp is used only for transition to / from disabled state. PLL frequency in NA mode is still changed under bypass only. This commit kept NA mode disabled. Bug 1555318 Change-Id: I91f5722a485d1b66b6113aa9c35a2fe36c38ea80 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/500637 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gm20b/clk_gm20b.c')
-rw-r--r--drivers/gpu/nvgpu/gm20b/clk_gm20b.c75
1 files changed, 64 insertions, 11 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
index 6f7d04dd..adf5136a 100644
--- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
@@ -56,6 +56,7 @@ static struct pll_parms gpc_pll_params = {
56#ifdef CONFIG_DEBUG_FS 56#ifdef CONFIG_DEBUG_FS
57static int clk_gm20b_debugfs_init(struct gk20a *g); 57static int clk_gm20b_debugfs_init(struct gk20a *g);
58#endif 58#endif
59static void clk_setup_slide(struct gk20a *g, u32 clk_u);
59 60
60#define DUMP_REG(addr_func) \ 61#define DUMP_REG(addr_func) \
61do { \ 62do { \
@@ -433,6 +434,12 @@ static int clk_enbale_pll_dvfs(struct gk20a *g)
433 gk20a_readl(g, trim_sys_gpcpll_cfg_r()); 434 gk20a_readl(g, trim_sys_gpcpll_cfg_r());
434 udelay(delay); 435 udelay(delay);
435 436
437 /*
438 * Dynamic ramp setup based on update rate, which in DVFS mode on GM20b
439 * is always 38.4 MHz, the same as reference clock rate.
440 */
441 clk_setup_slide(g, g->clk.gpc_pll.clk_in);
442
436 if (calibrated) 443 if (calibrated)
437 return 0; 444 return 0;
438 445
@@ -506,7 +513,7 @@ static void clk_setup_slide(struct gk20a *g, u32 clk_u)
506static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll) 513static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll)
507{ 514{
508 u32 data, coeff; 515 u32 data, coeff;
509 u32 nold; 516 u32 nold, sdm_old;
510 int ramp_timeout = 500; 517 int ramp_timeout = 500;
511 518
512 /* get old coefficients */ 519 /* get old coefficients */
@@ -514,11 +521,20 @@ static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll)
514 nold = trim_sys_gpcpll_coeff_ndiv_v(coeff); 521 nold = trim_sys_gpcpll_coeff_ndiv_v(coeff);
515 522
516 /* do nothing if NDIV is same */ 523 /* do nothing if NDIV is same */
517 if (gpll->N == nold) 524 if (gpll->mode == GPC_PLL_MODE_DVFS) {
518 return 0; 525 /* in DVFS mode check both integer and fraction */
526 coeff = gk20a_readl(g, trim_sys_gpcpll_cfg2_r());
527 sdm_old = trim_sys_gpcpll_cfg2_sdm_din_v(coeff);
528 if ((gpll->dvfs.n_int == nold) &&
529 (gpll->dvfs.sdm_din == sdm_old))
530 return 0;
531 } else {
532 if (gpll->N == nold)
533 return 0;
519 534
520 /* dynamic ramp setup based on update rate */ 535 /* dynamic ramp setup based on update rate */
521 clk_setup_slide(g, gpll->clk_in / gpll->M); 536 clk_setup_slide(g, gpll->clk_in / gpll->M);
537 }
522 538
523 /* pll slowdown mode */ 539 /* pll slowdown mode */
524 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r()); 540 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
@@ -528,11 +544,25 @@ static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll)
528 gk20a_writel(g, trim_sys_gpcpll_ndiv_slowdown_r(), data); 544 gk20a_writel(g, trim_sys_gpcpll_ndiv_slowdown_r(), data);
529 545
530 /* new ndiv ready for ramp */ 546 /* new ndiv ready for ramp */
531 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r()); 547 if (gpll->mode == GPC_PLL_MODE_DVFS) {
532 coeff = set_field(coeff, trim_sys_gpcpll_coeff_ndiv_m(), 548 /* in DVFS mode SDM is updated via "new" field */
533 trim_sys_gpcpll_coeff_ndiv_f(gpll->N)); 549 coeff = gk20a_readl(g, trim_sys_gpcpll_cfg2_r());
534 udelay(1); 550 coeff = set_field(coeff, trim_sys_gpcpll_cfg2_sdm_din_new_m(),
535 gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff); 551 trim_sys_gpcpll_cfg2_sdm_din_new_f(gpll->dvfs.sdm_din));
552 gk20a_writel(g, trim_sys_gpcpll_cfg2_r(), coeff);
553
554 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
555 coeff = set_field(coeff, trim_sys_gpcpll_coeff_ndiv_m(),
556 trim_sys_gpcpll_coeff_ndiv_f(gpll->dvfs.n_int));
557 udelay(1);
558 gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff);
559 } else {
560 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
561 coeff = set_field(coeff, trim_sys_gpcpll_coeff_ndiv_m(),
562 trim_sys_gpcpll_coeff_ndiv_f(gpll->N));
563 udelay(1);
564 gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff);
565 }
536 566
537 /* dynamic ramp to new ndiv */ 567 /* dynamic ramp to new ndiv */
538 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r()); 568 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
@@ -551,6 +581,14 @@ static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll)
551 break; 581 break;
552 } while (ramp_timeout > 0); 582 } while (ramp_timeout > 0);
553 583
584 if ((gpll->mode == GPC_PLL_MODE_DVFS) && (ramp_timeout > 0)) {
585 /* in DVFS mode complete SDM update */
586 coeff = gk20a_readl(g, trim_sys_gpcpll_cfg2_r());
587 coeff = set_field(coeff, trim_sys_gpcpll_cfg2_sdm_din_m(),
588 trim_sys_gpcpll_cfg2_sdm_din_f(gpll->dvfs.sdm_din));
589 gk20a_writel(g, trim_sys_gpcpll_cfg2_r(), coeff);
590 }
591
554 /* exit slowdown mode */ 592 /* exit slowdown mode */
555 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r()); 593 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
556 data = set_field(data, 594 data = set_field(data,
@@ -725,6 +763,10 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
725 gpll.PL = trim_sys_gpcpll_coeff_pldiv_v(coeff); 763 gpll.PL = trim_sys_gpcpll_coeff_pldiv_v(coeff);
726 gpll.clk_in = gpll_new->clk_in; 764 gpll.clk_in = gpll_new->clk_in;
727 765
766 /* combine target dvfs with old coefficients */
767 gpll.dvfs = gpll_new->dvfs;
768 gpll.mode = gpll_new->mode;
769
728 /* do NDIV slide if there is no change in M and PL */ 770 /* do NDIV slide if there is no change in M and PL */
729 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); 771 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
730 can_slide = allow_slide && trim_sys_gpcpll_cfg_enable_v(cfg); 772 can_slide = allow_slide && trim_sys_gpcpll_cfg_enable_v(cfg);
@@ -737,6 +779,8 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
737 int ret; 779 int ret;
738 gpll.N = DIV_ROUND_UP(gpll.M * gpc_pll_params.min_vco, 780 gpll.N = DIV_ROUND_UP(gpll.M * gpc_pll_params.min_vco,
739 gpll.clk_in); 781 gpll.clk_in);
782 if (gpll.mode == GPC_PLL_MODE_DVFS)
783 clk_config_dvfs_ndiv(gpll.dvfs.mv, gpll.N, &gpll.dvfs);
740 ret = clk_slide_gpc_pll(g, &gpll); 784 ret = clk_slide_gpc_pll(g, &gpll);
741 if (ret) 785 if (ret)
742 return ret; 786 return ret;
@@ -785,9 +829,12 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
785 * at 1:2 if either entry, or exit PL setting is 1:1. 829 * at 1:2 if either entry, or exit PL setting is 1:1.
786 */ 830 */
787 gpll = *gpll_new; 831 gpll = *gpll_new;
788 if (allow_slide) 832 if (allow_slide) {
789 gpll.N = DIV_ROUND_UP(gpll_new->M * gpc_pll_params.min_vco, 833 gpll.N = DIV_ROUND_UP(gpll_new->M * gpc_pll_params.min_vco,
790 gpll_new->clk_in); 834 gpll_new->clk_in);
835 if (gpll.mode == GPC_PLL_MODE_DVFS)
836 clk_config_dvfs_ndiv(gpll.dvfs.mv, gpll.N, &gpll.dvfs);
837 }
791 if (pldiv_only) 838 if (pldiv_only)
792 clk_change_pldiv_under_bypass(g, &gpll); 839 clk_change_pldiv_under_bypass(g, &gpll);
793 else 840 else
@@ -827,6 +874,9 @@ static int clk_program_na_gpc_pll(struct gk20a *g, struct pll *gpll_new,
827{ 874{
828 clk_config_dvfs(g, gpll_new); 875 clk_config_dvfs(g, gpll_new);
829 876
877 if (!gpll_new->enabled)
878 return clk_program_gpc_pll(g, gpll_new, allow_slide);
879
830 /* always under bypass, for now */ 880 /* always under bypass, for now */
831 return clk_program_gpc_pll(g, gpll_new, 0); 881 return clk_program_gpc_pll(g, gpll_new, 0);
832} 882}
@@ -844,6 +894,8 @@ static int clk_disable_gpcpll(struct gk20a *g, int allow_slide)
844 gpll.M = trim_sys_gpcpll_coeff_mdiv_v(coeff); 894 gpll.M = trim_sys_gpcpll_coeff_mdiv_v(coeff);
845 gpll.N = DIV_ROUND_UP(gpll.M * gpc_pll_params.min_vco, 895 gpll.N = DIV_ROUND_UP(gpll.M * gpc_pll_params.min_vco,
846 gpll.clk_in); 896 gpll.clk_in);
897 if (gpll.mode == GPC_PLL_MODE_DVFS)
898 clk_config_dvfs_ndiv(gpll.dvfs.mv, gpll.N, &gpll.dvfs);
847 clk_slide_gpc_pll(g, &gpll); 899 clk_slide_gpc_pll(g, &gpll);
848 } 900 }
849 901
@@ -867,6 +919,7 @@ static int clk_disable_gpcpll(struct gk20a *g, int allow_slide)
867 gk20a_readl(g, trim_sys_gpcpll_cfg_r()); 919 gk20a_readl(g, trim_sys_gpcpll_cfg_r());
868 920
869 clk->gpc_pll.enabled = false; 921 clk->gpc_pll.enabled = false;
922 clk->gpc_pll_last.enabled = false;
870 return 0; 923 return 0;
871} 924}
872 925