summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2014-07-25 00:44:59 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:10:37 -0400
commit1954c2ae8736cdef8e423be05dab48d64ac131d8 (patch)
tree6f8a0b458502f23ed320e86956648195c04fc704 /drivers/gpu/nvgpu/gm20b/clk_gm20b.c
parent14f47ad1f01fe7dce06081072bc8a03ea80841c2 (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/clk_gm20b.c')
-rw-r--r--drivers/gpu/nvgpu/gm20b/clk_gm20b.c63
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 */
35static struct pll_parms gpc_pll_params = { 35static 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
45static int clk_gm20b_debugfs_init(struct gk20a *g); 45static int clk_gm20b_debugfs_init(struct gk20a *g);
46#endif 46#endif
47 47
48static 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 */ 49static 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
54static 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; */
58static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll, 65static 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);