diff options
author | Alex Frid <afrid@nvidia.com> | 2014-07-25 00:44:59 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:10:37 -0400 |
commit | 1954c2ae8736cdef8e423be05dab48d64ac131d8 (patch) | |
tree | 6f8a0b458502f23ed320e86956648195c04fc704 /drivers/gpu/nvgpu/gm20b | |
parent | 14f47ad1f01fe7dce06081072bc8a03ea80841c2 (diff) |
gpu: nvgpu: Update GM20b GPCPLL parameters
Updated GPCPLL parameters according to GM20b specification.
Modified PLL programming, since on GM20b PLL post divider value is
equal to divider setting (which was not the case on GK20a this code
was inherited from).
Bug 1450787
Change-Id: Ia455ac49040047a3dbcd5d5211f2fbc71dc332ae
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/447751
GVS: Gerrit_Virtual_Submit
Reviewed-by: Hoang Pham <hopham@nvidia.com>
Tested-by: Hoang Pham <hopham@nvidia.com>
Reviewed-by: Seshendra Gadagottu <sgadagottu@nvidia.com>
Tested-by: Seshendra Gadagottu <sgadagottu@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gm20b')
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/clk_gm20b.c | 63 |
1 files changed, 29 insertions, 34 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c index 8e37047e..7fc4b8fb 100644 --- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c | |||
@@ -33,27 +33,34 @@ | |||
33 | 33 | ||
34 | /* from vbios PLL info table */ | 34 | /* from vbios PLL info table */ |
35 | static struct pll_parms gpc_pll_params = { | 35 | static struct pll_parms gpc_pll_params = { |
36 | 144000, 2064000, /* freq */ | 36 | 128000, 2600000, /* freq */ |
37 | 1000000, 2064000, /* vco */ | 37 | 1300000, 2600000, /* vco */ |
38 | 12000, 38000, /* u */ | 38 | 12000, 38400, /* u */ |
39 | 1, 255, /* M */ | 39 | 1, 255, /* M */ |
40 | 8, 255, /* N */ | 40 | 8, 255, /* N */ |
41 | 1, 32, /* PL */ | 41 | 1, 31, /* PL */ |
42 | }; | 42 | }; |
43 | 43 | ||
44 | #ifdef CONFIG_DEBUG_FS | 44 | #ifdef CONFIG_DEBUG_FS |
45 | static int clk_gm20b_debugfs_init(struct gk20a *g); | 45 | static int clk_gm20b_debugfs_init(struct gk20a *g); |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | static u8 pl_to_div[] = { | 48 | /* 1:1 match between post divider settings and divisor value */ |
49 | /* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ | 49 | static inline u32 pl_to_div(u32 pl) |
50 | /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32 }; | 50 | { |
51 | return pl; | ||
52 | } | ||
53 | |||
54 | static inline u32 div_to_pl(u32 div) | ||
55 | { | ||
56 | return div; | ||
57 | } | ||
51 | 58 | ||
52 | /* Calculate and update M/N/PL as well as pll->freq | 59 | /* Calculate and update M/N/PL as well as pll->freq |
53 | ref_clk_f = clk_in_f / src_div = clk_in_f; (src_div = 1 on gk20a) | 60 | ref_clk_f = clk_in_f; |
54 | u_f = ref_clk_f / M; | 61 | u_f = ref_clk_f / M; |
55 | PLL output = vco_f = u_f * N = ref_clk_f * N / M; | 62 | vco_f = u_f * N = ref_clk_f * N / M; |
56 | gpc2clk = target clock frequency = vco_f / PL; | 63 | PLL output = gpc2clk = target clock frequency = vco_f / pl_to_pdiv(PL); |
57 | gpcclk = gpc2clk / 2; */ | 64 | gpcclk = gpc2clk / 2; */ |
58 | static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll, | 65 | static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll, |
59 | struct pll_parms *pll_params, u32 *target_freq, bool best_fit) | 66 | struct pll_parms *pll_params, u32 *target_freq, bool best_fit) |
@@ -65,7 +72,7 @@ static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll, | |||
65 | u32 target_vco_f, vco_f; | 72 | u32 target_vco_f, vco_f; |
66 | u32 ref_clk_f, target_clk_f, u_f; | 73 | u32 ref_clk_f, target_clk_f, u_f; |
67 | u32 delta, lwv, best_delta = ~0; | 74 | u32 delta, lwv, best_delta = ~0; |
68 | int pl; | 75 | u32 pl; |
69 | 76 | ||
70 | BUG_ON(target_freq == NULL); | 77 | BUG_ON(target_freq == NULL); |
71 | 78 | ||
@@ -83,32 +90,20 @@ static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll, | |||
83 | if (max_vco_f < target_vco_f) | 90 | if (max_vco_f < target_vco_f) |
84 | max_vco_f = target_vco_f; | 91 | max_vco_f = target_vco_f; |
85 | 92 | ||
86 | high_PL = (max_vco_f + target_vco_f - 1) / target_vco_f; | 93 | /* Set PL search boundaries. */ |
94 | high_PL = div_to_pl((max_vco_f + target_vco_f - 1) / target_vco_f); | ||
87 | high_PL = min(high_PL, pll_params->max_PL); | 95 | high_PL = min(high_PL, pll_params->max_PL); |
88 | high_PL = max(high_PL, pll_params->min_PL); | 96 | high_PL = max(high_PL, pll_params->min_PL); |
89 | 97 | ||
90 | low_PL = min_vco_f / target_vco_f; | 98 | low_PL = div_to_pl(min_vco_f / target_vco_f); |
91 | low_PL = min(low_PL, pll_params->max_PL); | 99 | low_PL = min(low_PL, pll_params->max_PL); |
92 | low_PL = max(low_PL, pll_params->min_PL); | 100 | low_PL = max(low_PL, pll_params->min_PL); |
93 | 101 | ||
94 | /* Find Indices of high_PL and low_PL */ | ||
95 | for (pl = 0; pl < 14; pl++) { | ||
96 | if (pl_to_div[pl] >= low_PL) { | ||
97 | low_PL = pl; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | for (pl = 0; pl < 14; pl++) { | ||
102 | if (pl_to_div[pl] >= high_PL) { | ||
103 | high_PL = pl; | ||
104 | break; | ||
105 | } | ||
106 | } | ||
107 | gk20a_dbg_info("low_PL %d(div%d), high_PL %d(div%d)", | 102 | gk20a_dbg_info("low_PL %d(div%d), high_PL %d(div%d)", |
108 | low_PL, pl_to_div[low_PL], high_PL, pl_to_div[high_PL]); | 103 | low_PL, pl_to_div(low_PL), high_PL, pl_to_div(high_PL)); |
109 | 104 | ||
110 | for (pl = low_PL; pl <= high_PL; pl++) { | 105 | for (pl = low_PL; pl <= high_PL; pl++) { |
111 | target_vco_f = target_clk_f * pl_to_div[pl]; | 106 | target_vco_f = target_clk_f * pl_to_div(pl); |
112 | 107 | ||
113 | for (m = pll_params->min_M; m <= pll_params->max_M; m++) { | 108 | for (m = pll_params->min_M; m <= pll_params->max_M; m++) { |
114 | u_f = ref_clk_f / m; | 109 | u_f = ref_clk_f / m; |
@@ -133,8 +128,8 @@ static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll, | |||
133 | vco_f = ref_clk_f * n / m; | 128 | vco_f = ref_clk_f * n / m; |
134 | 129 | ||
135 | if (vco_f >= min_vco_f && vco_f <= max_vco_f) { | 130 | if (vco_f >= min_vco_f && vco_f <= max_vco_f) { |
136 | lwv = (vco_f + (pl_to_div[pl] / 2)) | 131 | lwv = (vco_f + (pl_to_div(pl) / 2)) |
137 | / pl_to_div[pl]; | 132 | / pl_to_div(pl); |
138 | delta = abs(lwv - target_clk_f); | 133 | delta = abs(lwv - target_clk_f); |
139 | 134 | ||
140 | if (delta < best_delta) { | 135 | if (delta < best_delta) { |
@@ -169,12 +164,12 @@ found_match: | |||
169 | pll->PL = best_PL; | 164 | pll->PL = best_PL; |
170 | 165 | ||
171 | /* save current frequency */ | 166 | /* save current frequency */ |
172 | pll->freq = ref_clk_f * pll->N / (pll->M * pl_to_div[pll->PL]); | 167 | pll->freq = ref_clk_f * pll->N / (pll->M * pl_to_div(pll->PL)); |
173 | 168 | ||
174 | *target_freq = pll->freq; | 169 | *target_freq = pll->freq; |
175 | 170 | ||
176 | gk20a_dbg_clk("actual target freq %d MHz, M %d, N %d, PL %d(div%d)", | 171 | gk20a_dbg_clk("actual target freq %d MHz, M %d, N %d, PL %d(div%d)", |
177 | *target_freq, pll->M, pll->N, pll->PL, pl_to_div[pll->PL]); | 172 | *target_freq, pll->M, pll->N, pll->PL, pl_to_div(pll->PL)); |
178 | 173 | ||
179 | gk20a_dbg_fn("done"); | 174 | gk20a_dbg_fn("done"); |
180 | 175 | ||
@@ -465,7 +460,7 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
465 | clk->gpc_pll.clk_in); | 460 | clk->gpc_pll.clk_in); |
466 | clk->gpc_pll.PL = 3; | 461 | clk->gpc_pll.PL = 3; |
467 | clk->gpc_pll.freq = clk->gpc_pll.clk_in * clk->gpc_pll.N; | 462 | clk->gpc_pll.freq = clk->gpc_pll.clk_in * clk->gpc_pll.N; |
468 | clk->gpc_pll.freq /= pl_to_div[clk->gpc_pll.PL]; | 463 | clk->gpc_pll.freq /= pl_to_div(clk->gpc_pll.PL); |
469 | } | 464 | } |
470 | 465 | ||
471 | mutex_init(&clk->clk_mutex); | 466 | mutex_init(&clk->clk_mutex); |
@@ -744,7 +739,7 @@ static int pll_reg_show(struct seq_file *s, void *data) | |||
744 | m = trim_sys_gpcpll_coeff_mdiv_v(reg); | 739 | m = trim_sys_gpcpll_coeff_mdiv_v(reg); |
745 | n = trim_sys_gpcpll_coeff_ndiv_v(reg); | 740 | n = trim_sys_gpcpll_coeff_ndiv_v(reg); |
746 | pl = trim_sys_gpcpll_coeff_pldiv_v(reg); | 741 | pl = trim_sys_gpcpll_coeff_pldiv_v(reg); |
747 | f = g->clk.gpc_pll.clk_in * n / (m * pl_to_div[pl]); | 742 | f = g->clk.gpc_pll.clk_in * n / (m * pl_to_div(pl)); |
748 | seq_printf(s, "coef = 0x%x : m = %u : n = %u : pl = %u", reg, m, n, pl); | 743 | seq_printf(s, "coef = 0x%x : m = %u : n = %u : pl = %u", reg, m, n, pl); |
749 | seq_printf(s, " : pll_f(gpu_f) = %u(%u) kHz\n", f, f/2); | 744 | seq_printf(s, " : pll_f(gpu_f) = %u(%u) kHz\n", f, f/2); |
750 | mutex_unlock(&g->clk.clk_mutex); | 745 | mutex_unlock(&g->clk.clk_mutex); |