diff options
-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); |