summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
diff options
context:
space:
mode:
authorHoang Pham <hopham@nvidia.com>2014-07-21 18:21:56 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:10:33 -0400
commitf7642ca185356f9f5593dad475a710b965d9826b (patch)
tree8053f02e6f145d6870c5a0788ce5057a7d3cba1c /drivers/gpu/nvgpu/gm20b/clk_gm20b.c
parentb972f8d15eca74d91b932f16b09aacb893e110a8 (diff)
gpu: nvgpu: Fork GM20B clock from GK20A clock
Bug 1450787 Change-Id: Id7fb699d9129a272286d6bc93e0e95844440a628 Signed-off-by: Hoang Pham <hopham@nvidia.com> Reviewed-on: http://git-master/r/440536 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.c789
1 files changed, 788 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
index 848e4682..b8fc58bf 100644
--- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
@@ -26,9 +26,796 @@
26#include "gk20a/gk20a.h" 26#include "gk20a/gk20a.h"
27#include "gk20a/hw_trim_gk20a.h" 27#include "gk20a/hw_trim_gk20a.h"
28#include "gk20a/hw_timer_gk20a.h" 28#include "gk20a/hw_timer_gk20a.h"
29#include "clk_gm20b.h"
30
31#define gk20a_dbg_clk(fmt, arg...) \
32 gk20a_dbg(gpu_dbg_clk, fmt, ##arg)
33
34/* from vbios PLL info table */
35static struct pll_parms gpc_pll_params = {
36 144000, 2064000, /* freq */
37 1000000, 2064000, /* vco */
38 12000, 38000, /* u */
39 1, 255, /* M */
40 8, 255, /* N */
41 1, 32, /* PL */
42};
43
44#ifdef CONFIG_DEBUG_FS
45static int clk_gm20b_debugfs_init(struct gk20a *g);
46#endif
47
48static u8 pl_to_div[] = {
49/* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */
50/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32 };
51
52/* 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)
54 u_f = ref_clk_f / M;
55 PLL output = vco_f = u_f * N = ref_clk_f * N / M;
56 gpc2clk = target clock frequency = vco_f / PL;
57 gpcclk = gpc2clk / 2; */
58static int clk_config_pll(struct clk_gk20a *clk, struct pll *pll,
59 struct pll_parms *pll_params, u32 *target_freq, bool best_fit)
60{
61 u32 min_vco_f, max_vco_f;
62 u32 best_M, best_N;
63 u32 low_PL, high_PL, best_PL;
64 u32 m, n, n2;
65 u32 target_vco_f, vco_f;
66 u32 ref_clk_f, target_clk_f, u_f;
67 u32 delta, lwv, best_delta = ~0;
68 int pl;
69
70 BUG_ON(target_freq == NULL);
71
72 gk20a_dbg_fn("request target freq %d MHz", *target_freq);
73
74 ref_clk_f = pll->clk_in;
75 target_clk_f = *target_freq;
76 max_vco_f = pll_params->max_vco;
77 min_vco_f = pll_params->min_vco;
78 best_M = pll_params->max_M;
79 best_N = pll_params->min_N;
80 best_PL = pll_params->min_PL;
81
82 target_vco_f = target_clk_f + target_clk_f / 50;
83 if (max_vco_f < target_vco_f)
84 max_vco_f = target_vco_f;
85
86 high_PL = (max_vco_f + target_vco_f - 1) / target_vco_f;
87 high_PL = min(high_PL, pll_params->max_PL);
88 high_PL = max(high_PL, pll_params->min_PL);
89
90 low_PL = min_vco_f / target_vco_f;
91 low_PL = min(low_PL, pll_params->max_PL);
92 low_PL = max(low_PL, pll_params->min_PL);
93
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)",
108 low_PL, pl_to_div[low_PL], high_PL, pl_to_div[high_PL]);
109
110 for (pl = low_PL; pl <= high_PL; pl++) {
111 target_vco_f = target_clk_f * pl_to_div[pl];
112
113 for (m = pll_params->min_M; m <= pll_params->max_M; m++) {
114 u_f = ref_clk_f / m;
115
116 if (u_f < pll_params->min_u)
117 break;
118 if (u_f > pll_params->max_u)
119 continue;
120
121 n = (target_vco_f * m) / ref_clk_f;
122 n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f;
123
124 if (n > pll_params->max_N)
125 break;
126
127 for (; n <= n2; n++) {
128 if (n < pll_params->min_N)
129 continue;
130 if (n > pll_params->max_N)
131 break;
132
133 vco_f = ref_clk_f * n / m;
134
135 if (vco_f >= min_vco_f && vco_f <= max_vco_f) {
136 lwv = (vco_f + (pl_to_div[pl] / 2))
137 / pl_to_div[pl];
138 delta = abs(lwv - target_clk_f);
139
140 if (delta < best_delta) {
141 best_delta = delta;
142 best_M = m;
143 best_N = n;
144 best_PL = pl;
145
146 if (best_delta == 0 ||
147 /* 0.45% for non best fit */
148 (!best_fit && (vco_f / best_delta > 218))) {
149 goto found_match;
150 }
151
152 gk20a_dbg_info("delta %d @ M %d, N %d, PL %d",
153 delta, m, n, pl);
154 }
155 }
156 }
157 }
158 }
159
160found_match:
161 BUG_ON(best_delta == ~0);
162
163 if (best_fit && best_delta != 0)
164 gk20a_dbg_clk("no best match for target @ %dMHz on gpc_pll",
165 target_clk_f);
166
167 pll->M = best_M;
168 pll->N = best_N;
169 pll->PL = best_PL;
170
171 /* save current frequency */
172 pll->freq = ref_clk_f * pll->N / (pll->M * pl_to_div[pll->PL]);
173
174 *target_freq = pll->freq;
175
176 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]);
178
179 gk20a_dbg_fn("done");
180
181 return 0;
182}
183
184static int clk_slide_gpc_pll(struct gk20a *g, u32 n)
185{
186 u32 data, coeff;
187 u32 nold;
188 int ramp_timeout = 500;
189
190 /* get old coefficients */
191 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
192 nold = trim_sys_gpcpll_coeff_ndiv_v(coeff);
193
194 /* do nothing if NDIV is same */
195 if (n == nold)
196 return 0;
197
198 /* setup */
199 data = gk20a_readl(g, trim_sys_gpcpll_cfg2_r());
200 data = set_field(data, trim_sys_gpcpll_cfg2_pll_stepa_m(),
201 trim_sys_gpcpll_cfg2_pll_stepa_f(0x2b));
202 gk20a_writel(g, trim_sys_gpcpll_cfg2_r(), data);
203 data = gk20a_readl(g, trim_sys_gpcpll_cfg3_r());
204 data = set_field(data, trim_sys_gpcpll_cfg3_pll_stepb_m(),
205 trim_sys_gpcpll_cfg3_pll_stepb_f(0xb));
206 gk20a_writel(g, trim_sys_gpcpll_cfg3_r(), data);
207
208 /* pll slowdown mode */
209 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
210 data = set_field(data,
211 trim_sys_gpcpll_ndiv_slowdown_slowdown_using_pll_m(),
212 trim_sys_gpcpll_ndiv_slowdown_slowdown_using_pll_yes_f());
213 gk20a_writel(g, trim_sys_gpcpll_ndiv_slowdown_r(), data);
214
215 /* new ndiv ready for ramp */
216 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
217 coeff = set_field(coeff, trim_sys_gpcpll_coeff_ndiv_m(),
218 trim_sys_gpcpll_coeff_ndiv_f(n));
219 udelay(1);
220 gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff);
221
222 /* dynamic ramp to new ndiv */
223 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
224 data = set_field(data,
225 trim_sys_gpcpll_ndiv_slowdown_en_dynramp_m(),
226 trim_sys_gpcpll_ndiv_slowdown_en_dynramp_yes_f());
227 udelay(1);
228 gk20a_writel(g, trim_sys_gpcpll_ndiv_slowdown_r(), data);
229
230 do {
231 udelay(1);
232 ramp_timeout--;
233 data = gk20a_readl(
234 g, trim_gpc_bcast_gpcpll_ndiv_slowdown_debug_r());
235 if (trim_gpc_bcast_gpcpll_ndiv_slowdown_debug_pll_dynramp_done_synced_v(data))
236 break;
237 } while (ramp_timeout > 0);
238
239 /* exit slowdown mode */
240 data = gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
241 data = set_field(data,
242 trim_sys_gpcpll_ndiv_slowdown_slowdown_using_pll_m(),
243 trim_sys_gpcpll_ndiv_slowdown_slowdown_using_pll_no_f());
244 data = set_field(data,
245 trim_sys_gpcpll_ndiv_slowdown_en_dynramp_m(),
246 trim_sys_gpcpll_ndiv_slowdown_en_dynramp_no_f());
247 gk20a_writel(g, trim_sys_gpcpll_ndiv_slowdown_r(), data);
248 gk20a_readl(g, trim_sys_gpcpll_ndiv_slowdown_r());
249
250 if (ramp_timeout <= 0) {
251 gk20a_err(dev_from_gk20a(g), "gpcpll dynamic ramp timeout");
252 return -ETIMEDOUT;
253 }
254 return 0;
255}
256
257static int clk_program_gpc_pll(struct gk20a *g, struct clk_gk20a *clk,
258 int allow_slide)
259{
260 u32 data, cfg, coeff, timeout;
261 u32 m, n, pl;
262 u32 nlo;
263
264 gk20a_dbg_fn("");
265
266 if (!tegra_platform_is_silicon())
267 return 0;
268
269 /* get old coefficients */
270 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
271 m = trim_sys_gpcpll_coeff_mdiv_v(coeff);
272 n = trim_sys_gpcpll_coeff_ndiv_v(coeff);
273 pl = trim_sys_gpcpll_coeff_pldiv_v(coeff);
274
275 /* do NDIV slide if there is no change in M and PL */
276 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
277 if (allow_slide && clk->gpc_pll.M == m && clk->gpc_pll.PL == pl
278 && trim_sys_gpcpll_cfg_enable_v(cfg)) {
279 return clk_slide_gpc_pll(g, clk->gpc_pll.N);
280 }
281
282 /* slide down to NDIV_LO */
283 nlo = DIV_ROUND_UP(m * gpc_pll_params.min_vco, clk->gpc_pll.clk_in);
284 if (allow_slide && trim_sys_gpcpll_cfg_enable_v(cfg)) {
285 int ret = clk_slide_gpc_pll(g, nlo);
286 if (ret)
287 return ret;
288 }
289
290 /* split FO-to-bypass jump in halfs by setting out divider 1:2 */
291 data = gk20a_readl(g, trim_sys_gpc2clk_out_r());
292 data = set_field(data, trim_sys_gpc2clk_out_vcodiv_m(),
293 trim_sys_gpc2clk_out_vcodiv_f(2));
294 gk20a_writel(g, trim_sys_gpc2clk_out_r(), data);
295
296 /* put PLL in bypass before programming it */
297 data = gk20a_readl(g, trim_sys_sel_vco_r());
298 data = set_field(data, trim_sys_sel_vco_gpc2clk_out_m(),
299 trim_sys_sel_vco_gpc2clk_out_bypass_f());
300 udelay(2);
301 gk20a_writel(g, trim_sys_sel_vco_r(), data);
302
303 /* get out from IDDQ */
304 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
305 if (trim_sys_gpcpll_cfg_iddq_v(cfg)) {
306 cfg = set_field(cfg, trim_sys_gpcpll_cfg_iddq_m(),
307 trim_sys_gpcpll_cfg_iddq_power_on_v());
308 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg);
309 gk20a_readl(g, trim_sys_gpcpll_cfg_r());
310 udelay(2);
311 }
312
313 /* disable PLL before changing coefficients */
314 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
315 cfg = set_field(cfg, trim_sys_gpcpll_cfg_enable_m(),
316 trim_sys_gpcpll_cfg_enable_no_f());
317 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg);
318 gk20a_readl(g, trim_sys_gpcpll_cfg_r());
319
320 /* change coefficients */
321 nlo = DIV_ROUND_UP(clk->gpc_pll.M * gpc_pll_params.min_vco,
322 clk->gpc_pll.clk_in);
323 coeff = trim_sys_gpcpll_coeff_mdiv_f(clk->gpc_pll.M) |
324 trim_sys_gpcpll_coeff_ndiv_f(allow_slide ?
325 nlo : clk->gpc_pll.N) |
326 trim_sys_gpcpll_coeff_pldiv_f(clk->gpc_pll.PL);
327 gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff);
328
329 /* enable PLL after changing coefficients */
330 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
331 cfg = set_field(cfg, trim_sys_gpcpll_cfg_enable_m(),
332 trim_sys_gpcpll_cfg_enable_yes_f());
333 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg);
334
335 /* lock pll */
336 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
337 if (cfg & trim_sys_gpcpll_cfg_enb_lckdet_power_off_f()){
338 cfg = set_field(cfg, trim_sys_gpcpll_cfg_enb_lckdet_m(),
339 trim_sys_gpcpll_cfg_enb_lckdet_power_on_f());
340 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg);
341 }
342
343 /* wait pll lock */
344 timeout = clk->pll_delay / 2 + 1;
345 do {
346 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
347 if (cfg & trim_sys_gpcpll_cfg_pll_lock_true_f())
348 goto pll_locked;
349 udelay(2);
350 } while (--timeout > 0);
351
352 /* PLL is messed up. What can we do here? */
353 BUG();
354 return -EBUSY;
355
356pll_locked:
357 /* put PLL back on vco */
358 data = gk20a_readl(g, trim_sys_sel_vco_r());
359 data = set_field(data, trim_sys_sel_vco_gpc2clk_out_m(),
360 trim_sys_sel_vco_gpc2clk_out_vco_f());
361 gk20a_writel(g, trim_sys_sel_vco_r(), data);
362 clk->gpc_pll.enabled = true;
363
364 /* restore out divider 1:1 */
365 data = gk20a_readl(g, trim_sys_gpc2clk_out_r());
366 data = set_field(data, trim_sys_gpc2clk_out_vcodiv_m(),
367 trim_sys_gpc2clk_out_vcodiv_by1_f());
368 udelay(2);
369 gk20a_writel(g, trim_sys_gpc2clk_out_r(), data);
370
371 /* slide up to target NDIV */
372 return clk_slide_gpc_pll(g, clk->gpc_pll.N);
373}
374
375static int clk_disable_gpcpll(struct gk20a *g, int allow_slide)
376{
377 u32 cfg, coeff, m, nlo;
378 struct clk_gk20a *clk = &g->clk;
379
380 /* slide to VCO min */
381 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
382 if (allow_slide && trim_sys_gpcpll_cfg_enable_v(cfg)) {
383 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
384 m = trim_sys_gpcpll_coeff_mdiv_v(coeff);
385 nlo = DIV_ROUND_UP(m * gpc_pll_params.min_vco,
386 clk->gpc_pll.clk_in);
387 clk_slide_gpc_pll(g, nlo);
388 }
389
390 /* put PLL in bypass before disabling it */
391 cfg = gk20a_readl(g, trim_sys_sel_vco_r());
392 cfg = set_field(cfg, trim_sys_sel_vco_gpc2clk_out_m(),
393 trim_sys_sel_vco_gpc2clk_out_bypass_f());
394 gk20a_writel(g, trim_sys_sel_vco_r(), cfg);
395
396 /* disable PLL */
397 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
398 cfg = set_field(cfg, trim_sys_gpcpll_cfg_enable_m(),
399 trim_sys_gpcpll_cfg_enable_no_f());
400 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg);
401 gk20a_readl(g, trim_sys_gpcpll_cfg_r());
402
403 clk->gpc_pll.enabled = false;
404 return 0;
405}
406
407static int gm20b_init_clk_reset_enable_hw(struct gk20a *g)
408{
409 gk20a_dbg_fn("");
410 return 0;
411}
412
413struct clk *gm20b_clk_get(struct gk20a *g)
414{
415 if (!g->clk.tegra_clk) {
416 struct clk *clk;
417
418 clk = clk_get_sys("tegra_gk20a", "gpu");
419 if (IS_ERR(clk)) {
420 gk20a_err(dev_from_gk20a(g),
421 "fail to get tegra gpu clk tegra_gk20a/gpu");
422 return NULL;
423 }
424 g->clk.tegra_clk = clk;
425 }
426
427 return g->clk.tegra_clk;
428}
429
430static int gm20b_init_clk_setup_sw(struct gk20a *g)
431{
432 struct clk_gk20a *clk = &g->clk;
433 static int initialized;
434 struct clk *ref;
435 unsigned long ref_rate;
436
437 gk20a_dbg_fn("");
438
439 if (clk->sw_ready) {
440 gk20a_dbg_fn("skip init");
441 return 0;
442 }
443
444 if (!gk20a_clk_get(g))
445 return -EINVAL;
446
447 ref = clk_get_parent(clk_get_parent(clk->tegra_clk));
448 if (IS_ERR(ref)) {
449 gk20a_err(dev_from_gk20a(g),
450 "failed to get GPCPLL reference clock");
451 return -EINVAL;
452 }
453 ref_rate = clk_get_rate(ref);
454
455 clk->pll_delay = 300; /* usec */
456
457 clk->gpc_pll.id = GK20A_GPC_PLL;
458 clk->gpc_pll.clk_in = ref_rate / KHZ;
459
460 /* Decide initial frequency */
461 if (!initialized) {
462 initialized = 1;
463 clk->gpc_pll.M = 1;
464 clk->gpc_pll.N = DIV_ROUND_UP(gpc_pll_params.min_vco,
465 clk->gpc_pll.clk_in);
466 clk->gpc_pll.PL = 1;
467 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];
469 }
470
471 mutex_init(&clk->clk_mutex);
472
473 clk->sw_ready = true;
474
475 gk20a_dbg_fn("done");
476 return 0;
477}
478
479static int gm20b_init_clk_setup_hw(struct gk20a *g)
480{
481 u32 data;
482
483 gk20a_dbg_fn("");
484
485 data = gk20a_readl(g, trim_sys_gpc2clk_out_r());
486 data = set_field(data,
487 trim_sys_gpc2clk_out_sdiv14_m() |
488 trim_sys_gpc2clk_out_vcodiv_m() |
489 trim_sys_gpc2clk_out_bypdiv_m(),
490 trim_sys_gpc2clk_out_sdiv14_indiv4_mode_f() |
491 trim_sys_gpc2clk_out_vcodiv_by1_f() |
492 trim_sys_gpc2clk_out_bypdiv_f(0));
493 gk20a_writel(g, trim_sys_gpc2clk_out_r(), data);
494
495 return 0;
496}
497
498static int set_pll_target(struct gk20a *g, u32 freq, u32 old_freq)
499{
500 struct clk_gk20a *clk = &g->clk;
501
502 if (freq > gpc_pll_params.max_freq)
503 freq = gpc_pll_params.max_freq;
504 else if (freq < gpc_pll_params.min_freq)
505 freq = gpc_pll_params.min_freq;
506
507 if (freq != old_freq) {
508 /* gpc_pll.freq is changed to new value here */
509 if (clk_config_pll(clk, &clk->gpc_pll, &gpc_pll_params,
510 &freq, true)) {
511 gk20a_err(dev_from_gk20a(g),
512 "failed to set pll target for %d", freq);
513 return -EINVAL;
514 }
515 }
516 return 0;
517}
518
519static int set_pll_freq(struct gk20a *g, u32 freq, u32 old_freq)
520{
521 struct clk_gk20a *clk = &g->clk;
522 int err = 0;
523
524 gk20a_dbg_fn("curr freq: %dMHz, target freq %dMHz", old_freq, freq);
525
526 if ((freq == old_freq) && clk->gpc_pll.enabled)
527 return 0;
528
529 /* change frequency only if power is on */
530 if (g->clk.clk_hw_on) {
531 err = clk_program_gpc_pll(g, clk, 1);
532 if (err)
533 err = clk_program_gpc_pll(g, clk, 0);
534 }
535
536 /* Just report error but not restore PLL since dvfs could already change
537 voltage even when it returns error. */
538 if (err)
539 gk20a_err(dev_from_gk20a(g),
540 "failed to set pll to %d", freq);
541 return err;
542}
543
544static int gm20b_clk_export_set_rate(void *data, unsigned long *rate)
545{
546 u32 old_freq;
547 int ret = -ENODATA;
548 struct gk20a *g = data;
549 struct clk_gk20a *clk = &g->clk;
550
551 if (rate) {
552 mutex_lock(&clk->clk_mutex);
553 old_freq = clk->gpc_pll.freq;
554 ret = set_pll_target(g, rate_gpu_to_gpc2clk(*rate), old_freq);
555 if (!ret && clk->gpc_pll.enabled)
556 ret = set_pll_freq(g, clk->gpc_pll.freq, old_freq);
557 if (!ret)
558 *rate = rate_gpc2clk_to_gpu(clk->gpc_pll.freq);
559 mutex_unlock(&clk->clk_mutex);
560 }
561 return ret;
562}
563
564static int gm20b_clk_export_enable(void *data)
565{
566 int ret;
567 struct gk20a *g = data;
568 struct clk_gk20a *clk = &g->clk;
569
570 mutex_lock(&clk->clk_mutex);
571 ret = set_pll_freq(g, clk->gpc_pll.freq, clk->gpc_pll.freq);
572 mutex_unlock(&clk->clk_mutex);
573 return ret;
574}
575
576static void gm20b_clk_export_disable(void *data)
577{
578 struct gk20a *g = data;
579 struct clk_gk20a *clk = &g->clk;
580
581 mutex_lock(&clk->clk_mutex);
582 if (g->clk.clk_hw_on)
583 clk_disable_gpcpll(g, 1);
584 mutex_unlock(&clk->clk_mutex);
585}
586
587static void gm20b_clk_export_init(void *data, unsigned long *rate, bool *state)
588{
589 struct gk20a *g = data;
590 struct clk_gk20a *clk = &g->clk;
591
592 mutex_lock(&clk->clk_mutex);
593 if (state)
594 *state = clk->gpc_pll.enabled;
595 if (rate)
596 *rate = rate_gpc2clk_to_gpu(clk->gpc_pll.freq);
597 mutex_unlock(&clk->clk_mutex);
598}
599
600static struct tegra_clk_export_ops gm20b_clk_export_ops = {
601 .init = gm20b_clk_export_init,
602 .enable = gm20b_clk_export_enable,
603 .disable = gm20b_clk_export_disable,
604 .set_rate = gm20b_clk_export_set_rate,
605};
606
607static int gm20b_clk_register_export_ops(struct gk20a *g)
608{
609 int ret;
610 struct clk *c;
611
612 if (gm20b_clk_export_ops.data)
613 return 0;
614
615 gm20b_clk_export_ops.data = (void *)g;
616 c = g->clk.tegra_clk;
617 if (!c || !clk_get_parent(c))
618 return -ENOSYS;
619
620 ret = tegra_clk_register_export_ops(clk_get_parent(c),
621 &gm20b_clk_export_ops);
622
623 return ret;
624}
625
626int gm20b_init_clk_support(struct gk20a *g)
627{
628 struct clk_gk20a *clk = &g->clk;
629 u32 err;
630
631 gk20a_dbg_fn("");
632
633 clk->g = g;
634
635 err = gm20b_init_clk_reset_enable_hw(g);
636 if (err)
637 return err;
638
639 err = gm20b_init_clk_setup_sw(g);
640 if (err)
641 return err;
642
643 mutex_lock(&clk->clk_mutex);
644 clk->clk_hw_on = true;
645
646 err = gm20b_init_clk_setup_hw(g);
647 mutex_unlock(&clk->clk_mutex);
648 if (err)
649 return err;
650
651 err = gm20b_clk_register_export_ops(g);
652 if (err)
653 return err;
654
655 /* FIXME: this effectively prevents host level clock gating */
656 err = clk_enable(g->clk.tegra_clk);
657 if (err)
658 return err;
659
660 /* The prev call may not enable PLL if gbus is unbalanced - force it */
661 mutex_lock(&clk->clk_mutex);
662 err = set_pll_freq(g, clk->gpc_pll.freq, clk->gpc_pll.freq);
663 mutex_unlock(&clk->clk_mutex);
664 if (err)
665 return err;
666
667#ifdef CONFIG_DEBUG_FS
668 if (!clk->debugfs_set) {
669 if (!clk_gm20b_debugfs_init(g))
670 clk->debugfs_set = true;
671 }
672#endif
673 return err;
674}
29 675
30void gm20b_init_clk_ops(struct gpu_ops *gops) 676void gm20b_init_clk_ops(struct gpu_ops *gops)
31{ 677{
32 gops->clk.init_clk_support = gk20a_init_clk_support; 678 gops->clk.init_clk_support = gm20b_init_clk_support;
679 gops->clk.suspend_clk_support = gm20b_suspend_clk_support;
680}
681
682int gm20b_suspend_clk_support(struct gk20a *g)
683{
684 int ret;
685
686 clk_disable(g->clk.tegra_clk);
687
688 /* The prev call may not disable PLL if gbus is unbalanced - force it */
689 mutex_lock(&g->clk.clk_mutex);
690 ret = clk_disable_gpcpll(g, 1);
691 g->clk.clk_hw_on = false;
692 mutex_unlock(&g->clk.clk_mutex);
693 return ret;
694}
695
696#ifdef CONFIG_DEBUG_FS
697
698static int rate_get(void *data, u64 *val)
699{
700 struct gk20a *g = (struct gk20a *)data;
701 *val = (u64)gk20a_clk_get_rate(g);
702 return 0;
703}
704static int rate_set(void *data, u64 val)
705{
706 struct gk20a *g = (struct gk20a *)data;
707 return gk20a_clk_set_rate(g, (u32)val);
708}
709DEFINE_SIMPLE_ATTRIBUTE(rate_fops, rate_get, rate_set, "%llu\n");
710
711static int pll_reg_show(struct seq_file *s, void *data)
712{
713 struct gk20a *g = s->private;
714 u32 reg, m, n, pl, f;
715
716 mutex_lock(&g->clk.clk_mutex);
717 if (!g->clk.clk_hw_on) {
718 seq_printf(s, "gk20a powered down - no access to registers\n");
719 mutex_unlock(&g->clk.clk_mutex);
720 return 0;
721 }
722
723 reg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
724 seq_printf(s, "cfg = 0x%x : %s : %s\n", reg,
725 trim_sys_gpcpll_cfg_enable_v(reg) ? "enabled" : "disabled",
726 trim_sys_gpcpll_cfg_pll_lock_v(reg) ? "locked" : "unlocked");
727
728 reg = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
729 m = trim_sys_gpcpll_coeff_mdiv_v(reg);
730 n = trim_sys_gpcpll_coeff_ndiv_v(reg);
731 pl = trim_sys_gpcpll_coeff_pldiv_v(reg);
732 f = g->clk.gpc_pll.clk_in * n / (m * pl_to_div[pl]);
733 seq_printf(s, "coef = 0x%x : m = %u : n = %u : pl = %u", reg, m, n, pl);
734 seq_printf(s, " : pll_f(gpu_f) = %u(%u) kHz\n", f, f/2);
735 mutex_unlock(&g->clk.clk_mutex);
736 return 0;
737}
738
739static int pll_reg_open(struct inode *inode, struct file *file)
740{
741 return single_open(file, pll_reg_show, inode->i_private);
742}
743
744static const struct file_operations pll_reg_fops = {
745 .open = pll_reg_open,
746 .read = seq_read,
747 .llseek = seq_lseek,
748 .release = single_release,
749};
750
751static int monitor_get(void *data, u64 *val)
752{
753 struct gk20a *g = (struct gk20a *)data;
754 struct clk_gk20a *clk = &g->clk;
755 int err;
756
757 u32 ncycle = 100; /* count GPCCLK for ncycle of clkin */
758 u64 freq = clk->gpc_pll.clk_in;
759 u32 count1, count2;
760
761 err = gk20a_busy(g->dev);
762 if (err)
763 return err;
764
765 gk20a_writel(g, trim_gpc_clk_cntr_ncgpcclk_cfg_r(0),
766 trim_gpc_clk_cntr_ncgpcclk_cfg_reset_asserted_f());
767 gk20a_writel(g, trim_gpc_clk_cntr_ncgpcclk_cfg_r(0),
768 trim_gpc_clk_cntr_ncgpcclk_cfg_enable_asserted_f() |
769 trim_gpc_clk_cntr_ncgpcclk_cfg_write_en_asserted_f() |
770 trim_gpc_clk_cntr_ncgpcclk_cfg_noofipclks_f(ncycle));
771 /* start */
772
773 /* It should take about 8us to finish 100 cycle of 12MHz.
774 But longer than 100us delay is required here. */
775 gk20a_readl(g, trim_gpc_clk_cntr_ncgpcclk_cfg_r(0));
776 udelay(2000);
777
778 count1 = gk20a_readl(g, trim_gpc_clk_cntr_ncgpcclk_cnt_r(0));
779 udelay(100);
780 count2 = gk20a_readl(g, trim_gpc_clk_cntr_ncgpcclk_cnt_r(0));
781 freq *= trim_gpc_clk_cntr_ncgpcclk_cnt_value_v(count2);
782 do_div(freq, ncycle);
783 *val = freq;
784
785 gk20a_idle(g->dev);
786
787 if (count1 != count2)
788 return -EBUSY;
789 return 0;
790}
791DEFINE_SIMPLE_ATTRIBUTE(monitor_fops, monitor_get, NULL, "%llu\n");
792
793static int clk_gm20b_debugfs_init(struct gk20a *g)
794{
795 struct dentry *d;
796 struct gk20a_platform *platform = platform_get_drvdata(g->dev);
797
798 d = debugfs_create_file(
799 "rate", S_IRUGO|S_IWUSR, platform->debugfs, g, &rate_fops);
800 if (!d)
801 goto err_out;
802
803 d = debugfs_create_file(
804 "pll_reg", S_IRUGO, platform->debugfs, g, &pll_reg_fops);
805 if (!d)
806 goto err_out;
807
808 d = debugfs_create_file(
809 "monitor", S_IRUGO, platform->debugfs, g, &monitor_fops);
810 if (!d)
811 goto err_out;
812
813 return 0;
814
815err_out:
816 pr_err("%s: Failed to make debugfs node\n", __func__);
817 debugfs_remove_recursive(platform->debugfs);
818 return -ENOMEM;
33} 819}
34 820
821#endif /* CONFIG_DEBUG_FS */